/*
 *  Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Library General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "chalkcoremodule.h"

#include <kdebug.h>

//#include <api/variant.h>
#include <api/qtobject.h>
#include <main/manager.h>

#include <kis_autobrush_resource.h>
#include <kis_brush.h>
#include <kis_colorspace_factory_registry.h>
#include <kis_doc.h>
#include <kis_filter.h>
#include <kis_filter_registry.h>
#include <kis_image.h>
#include <kis_meta_registry.h>
#include <kis_pattern.h>
#include <kis_resourceserver.h>

#include "kis_script_progress.h"

#include "krs_brush.h"
#include "krs_color.h"
#include "krs_doc.h"
#include "krs_filter.h"
#include "krs_image.h"
#include "krs_pattern.h"
#include "krs_script_progress.h"

extern "C"
{
    /**
     * Exported an loadable function as entry point to use
     * the \a KexiAppModule.
     */
    Kross::Api::Object* TDE_EXPORT init_module(Kross::Api::Manager* manager)
    {
        return new Kross::ChalkCore::ChalkCoreModule(manager);
    }
}


using namespace Kross::ChalkCore;

ChalkCoreFactory::ChalkCoreFactory(TQString packagePath) : Kross::Api::Event<ChalkCoreFactory>("ChalkCoreFactory"), m_packagePath(packagePath)
{
    addFunction("newRGBColor", &ChalkCoreFactory::newRGBColor);
    addFunction("newHSVColor", &ChalkCoreFactory::newHSVColor);
    addFunction("getPattern", &ChalkCoreFactory::getPattern);
    addFunction("loadPattern", &ChalkCoreFactory::loadPattern);
    addFunction("getBrush", &ChalkCoreFactory::getBrush);
    addFunction("loadBrush", &ChalkCoreFactory::loadBrush);
    addFunction("getFilter", &ChalkCoreFactory::getFilter);
    addFunction("newCircleBrush", &ChalkCoreFactory::newCircleBrush);
    addFunction("newRectBrush", &ChalkCoreFactory::newRectBrush);
    addFunction("newImage", &ChalkCoreFactory::newImage);
    addFunction("getPackagePath", &ChalkCoreFactory::getPackagePath);
}

Kross::Api::Object::Ptr ChalkCoreFactory::newRGBColor(Kross::Api::List::Ptr args)
{
    Color* c = new Color(Kross::Api::Variant::toUInt(args->item(0)), Kross::Api::Variant::toUInt(args->item(1)), Kross::Api::Variant::toUInt(args->item(2)), TQColor::Rgb);
    return c;
}
Kross::Api::Object::Ptr ChalkCoreFactory::newHSVColor(Kross::Api::List::Ptr args)
{
    return new Color(Kross::Api::Variant::toUInt(args->item(0)), Kross::Api::Variant::toUInt(args->item(1)), Kross::Api::Variant::toUInt(args->item(2)), TQColor::Hsv);
}

Kross::Api::Object::Ptr ChalkCoreFactory::getPattern(Kross::Api::List::Ptr args)
{
    KisResourceServerBase* rServer = KisResourceServerRegistry::instance()->get("PatternServer");
    TQValueList<KisResource*> resources = rServer->resources();

    TQString name = Kross::Api::Variant::toString(args->item(0));

    for (TQValueList<KisResource*>::iterator it = resources.begin(); it != resources.end(); ++it )
    {
        if((*it)->name() == name)
        {
            return new Pattern(dynamic_cast<KisPattern*>(*it), true);
        }
    }
    throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(  i18n("Unknown pattern") ) );
    return 0;

}

Kross::Api::Object::Ptr ChalkCoreFactory::loadPattern(Kross::Api::List::Ptr args)
{
    TQString filename = Kross::Api::Variant::toString(args->item(0));
    KisPattern* pattern = new KisPattern(filename);
    if(pattern->load())
    {
        return new Pattern( pattern, false );
    } else {
        delete pattern;
        throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown pattern") ) );
        return 0;
    }
}

Kross::Api::Object::Ptr ChalkCoreFactory::getBrush(Kross::Api::List::Ptr args)
{
    KisResourceServerBase* rServer = KisResourceServerRegistry::instance()->get("BrushServer");
    TQValueList<KisResource*> resources = rServer->resources();

    TQString name = Kross::Api::Variant::toString(args->item(0));

    for (TQValueList<KisResource*>::iterator it = resources.begin(); it != resources.end(); ++it )
    {
        if((*it)->name() == name)
        {
            return new Brush(dynamic_cast<KisBrush*>(*it), true);
        }
    }
    throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown brush") ) );
    return 0;
}

Kross::Api::Object::Ptr ChalkCoreFactory::loadBrush(Kross::Api::List::Ptr args)
{
    TQString filename = Kross::Api::Variant::toString(args->item(0));
    KisBrush* brush = new KisBrush(filename);
    if(brush->load())
    {
        return new Brush( brush, false );
    } else {
        delete brush;
        throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown brush") ) );
        return 0;
    }
}

Kross::Api::Object::Ptr ChalkCoreFactory::getFilter(Kross::Api::List::Ptr args)
{
    TQString name = Kross::Api::Variant::toString(args->item(0));
    KisFilter* filter = KisFilterRegistry::instance()->get(name);
    if(filter)
    {
      return new Filter(filter);
    } else {
      return 0;
    }
}

Kross::Api::Object::Ptr ChalkCoreFactory::newCircleBrush(Kross::Api::List::Ptr args)
{
    uint w = TQMAX(1, Kross::Api::Variant::toUInt(args->item(0)));
    uint h = TQMAX(1, Kross::Api::Variant::toUInt(args->item(1)));
    uint hf = 0;
    uint vf = 0;
    if( args.count() > 2)
    {
        hf = Kross::Api::Variant::toUInt(args->item(2));
        vf = Kross::Api::Variant::toUInt(args->item(3));
    }
    KisAutobrushShape* kas = new KisAutobrushCircleShape(w, h, hf, vf);
    TQImage* brsh = new TQImage();
    kas->createBrush(brsh);
    return new Brush(new KisAutobrushResource(*brsh), false);
}
Kross::Api::Object::Ptr ChalkCoreFactory::newRectBrush(Kross::Api::List::Ptr args)
{
    uint w = TQMAX(1, Kross::Api::Variant::toUInt(args->item(0)));
    uint h = TQMAX(1, Kross::Api::Variant::toUInt(args->item(1)));
    uint hf = 0;
    uint vf = 0;
    if( args.count() > 2)
    {
        hf = Kross::Api::Variant::toUInt(args->item(2));
        vf = Kross::Api::Variant::toUInt(args->item(3));
    }
    KisAutobrushShape* kas = new KisAutobrushRectShape(w, h, hf, vf);
    TQImage* brsh = new TQImage();
    kas->createBrush(brsh);
    return new Brush(new KisAutobrushResource(*brsh), false);;
}

Kross::Api::Object::Ptr ChalkCoreFactory::newImage(Kross::Api::List::Ptr args)
{
    int w = Kross::Api::Variant::toInt(args->item(0));
    int h = Kross::Api::Variant::toInt(args->item(1));
    TQString csname = Kross::Api::Variant::toString(args->item(2));
    TQString name = Kross::Api::Variant::toString(args->item(3));
    if( w < 0 || h < 0)
    {
        throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Invalid image size") ) );
        return 0;
    }
    KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csname, ""), "");
    if(!cs)
    {
        throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Colorspace %0 is not available, please check your installation.").arg(csname ) ) );
        return 0;
    }

    return new Image(new KisImage(0,w,h, cs, name));
}

Kross::Api::Object::Ptr ChalkCoreFactory::getPackagePath(Kross::Api::List::Ptr)
{
    return new Kross::Api::Variant(m_packagePath);
}

ChalkCoreModule::ChalkCoreModule(Kross::Api::Manager* manager)
    : Kross::Api::Module("chalkcore") , m_manager(manager), m_factory(0)
{

    TQMap<TQString, Object::Ptr> children = manager->getChildren();
    kdDebug(41011) << " there are " << children.size() << endl;
    for(TQMap<TQString, Object::Ptr>::const_iterator it = children.begin(); it != children.end(); it++)
    {
        kdDebug(41011) << it.key() << " " << it.data() << endl;
    }

    // Wrap doc
    Kross::Api::Object::Ptr chalkdocument = manager->getChild("ChalkDocument");
    if(chalkdocument) {
        Kross::Api::QtObject* chalkdocumentqt = (Kross::Api::QtObject*)( chalkdocument.data() );
        if(chalkdocumentqt) {
            ::KisDoc* document = (::KisDoc*)( chalkdocumentqt->getObject() );
            if(document) {
                addChild( new Doc(document) );
            } else {
                throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("There was no 'ChalkDocument' published.") );
            }
         }
    }
   // Wrap ChalkScriptProgress
    TQString packagePath;
    Kross::Api::Object::Ptr chalkscriptprogress = manager->getChild("ChalkScriptProgress");
    if(chalkdocument) {
        Kross::Api::QtObject* chalkscriptprogressqt = (Kross::Api::QtObject*)( chalkscriptprogress.data() );
        if(chalkscriptprogressqt) {
                ::KisScriptProgress* scriptprogress = (::KisScriptProgress*)( chalkscriptprogressqt->getObject() );
                scriptprogress->activateAsSubject();
                packagePath = scriptprogress->packagePath();
                if(scriptprogress) {
                    addChild( new ScriptProgress(scriptprogress) );
                } else {
                    throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("There was no 'ChalkScriptProgress' published.") );
                }
        }
    }
    m_factory = new ChalkCoreFactory(packagePath);
}

ChalkCoreModule::~ChalkCoreModule()
{
    if(m_factory)
        delete m_factory;
}


const TQString ChalkCoreModule::getClassName() const
{
    return "Kross::ChalkCore::ChalkCoreModule";
}

Kross::Api::Object::Ptr ChalkCoreModule::call(const TQString& name, Kross::Api::List::Ptr arguments)
{
    kdDebug(41011) << "ChalkCoreModule::call = " << name << endl;
    if( m_factory->isAFunction(name))
    {
        return m_factory->call(name, arguments);
    } else {
        return Kross::Api::Module::call(name, arguments);
    }
}
