/***************************************************************************
 *   Copyright (C) 2005 by Daniel Stöckel                                  *
 *   the_docter@gmx.net                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "configuration.h"

#include <tqfile.h>
#include <tqwidgetstack.h>
#include <tqobjectlist.h>
#include <tqdir.h>

#include <kstandarddirs.h>
#include <kshell.h>
#include <kdebug.h>

#include "menulistviewitem.h"

Config::Config()
    :mTintColor(TQt::black),mOpacity(0.2f),mScheme("none"),mMenuButtonSize(32),mNavButtonSize(32),mMenuRadius(132),doc(NULL)
{
    mConfigPath = locate("data", "kommando/kommandorc");
    kdDebug() << "kommandorc located: " << mConfigPath << endl;

    if (mConfigPath.isNull() || !TQFile::exists(mConfigPath)){ //test for new config file
        kdDebug() << "There is no kommandorc in tdedirs" << endl;
        mConfigPath = locateLocal("data", "kommando/kommandorc");

        if(TQFile::exists(KShell::homeDir("")+"/.kommandorc")){ //tries old config file
            kdDebug() << "There is a kommandorc in homedir, moving it to " << mConfigPath << endl;
            TQDir dir;
            if (!dir.rename(KShell::homeDir("")+"/.kommandorc", mConfigPath)) {
                kdWarning() << "Moving ~/.kommandorc failed, creating a default one" << endl;
                createDefaultConfigFile();
            }
        } else {
            kdDebug() << "There is no kommandorc, creating a default one" << endl;
            createDefaultConfigFile();
        }
    }
}

Config::~Config()
{
    if(doc){
        delete doc;
    }
}

void Config::createDefaultConfigFile()
{
    setDefaultValues();
    writeConfigFile();
}

bool Config::readConfigFile( )
{
    TQFile file(mConfigPath);
    if(!file.open(IO_ReadOnly)){
        return false;
    }
    if(doc){
        delete doc;
    }
    doc = new TQDomDocument();
    doc->setContent( &file );
    file.close();

    if(doc){
        TQDomNode topLevelNode = doc->documentElement().firstChild();
        while(!topLevelNode.isNull()){
            if(topLevelNode.isElement()){
                TQDomElement elem = topLevelNode.toElement();
                if(elem.tagName()=="access"){
                    setShortcut(elem.text());
                } else if(elem.tagName()=="tintcolor"){
                    mTintColor.setNamedColor(elem.text());
                } else if(elem.tagName()=="opacity"){
                    mOpacity = elem.text().toFloat();
                }else if(elem.tagName()=="menubuttonsize"){
                    mMenuButtonSize=elem.text().toInt();
                }else if(elem.tagName()=="navbuttonsize"){
                    mNavButtonSize=elem.text().toInt();
                }else if(elem.tagName()=="menuradius"){
                    mMenuRadius=elem.text().toInt();
                }else if(elem.tagName()=="scheme"){
                    mScheme=elem.text();
                }
            }
            topLevelNode = topLevelNode.nextSibling();
        }
    }
    return true;
}

bool Config::writeConfigFile( )
{
    if(!doc){
        return false;
    }

    mConfigPath = locateLocal("data", "kommando/kommandorc");
    TQFile file(mConfigPath);
    if(!file.open(IO_WriteOnly)){
        return false;
    }
    TQTextStream str(&file);
    str << *doc;
    file.close();
    return true;
}

void Config::fromConfigDlg(KommandoViewList& listViews )
{
    if(doc){
        delete doc;
    }
    doc = new TQDomDocument();
    TQDomElement root=doc->createElement("root");
    doc->appendChild(root);

    newNode("access",root,Shortcut(),"method","shortcut");
    newNode("menubuttonsize",root,mMenuButtonSize);
    newNode("navbuttonsize",root,mNavButtonSize);
    newNode("tintcolor",root,tintColor().name());
    newNode("opacity",root,mOpacity);
    newNode("menuradius",root,static_cast<int>(mMenuRadius));
    newNode("scheme",root,mScheme);

    for(KommandoView* it = listViews.first(); it != 0; it = listViews.next()){
        if(it->childCount() > 0){
            TQDomElement node = newMenu(root,it->appName());
            TQListViewItem* temp = it->firstChild();
            while(temp){
                menuItemToXML(node,static_cast<MenuListViewItem*>(temp));
                temp=temp->nextSibling();
            }
            root.appendChild(node);
        }
    }
}

//ARGHHH!! I need this function because TQListView::lastItem returns not only top level items but also children of top level items
//It took me hours of my precious lifetime to figure that out!! _Terribly_ annoying -.-
TQListViewItem* lastChild(TQListView* view)
{
    TQListViewItem* temp=view->firstChild();
    TQListViewItem* item=NULL;
    while(temp!=NULL){
        item=temp;
        temp=temp->nextSibling();
    }
    return item;
}

void Config::toListView(KommandoViewList& listViews, TQWidgetStack* listViewParent)//TQListView* listView )
{
    if(doc){
        TQDomNode topLevelNode = doc->documentElement().firstChild();
        const TQObjectList *children = listViewParent->children();
        if (children != 0) {
            TQObjectListIterator it(*children);
            for (; *it != 0; ++it)
                listViewParent->removeWidget(static_cast<TQWidget*>(*it));
        }

        while(!topLevelNode.isNull()){
            if(topLevelNode.isElement()){
                if(topLevelNode.toElement().tagName()=="menu")
                {
                    KommandoView* view = new KommandoView(listViewParent,topLevelNode.toElement().attribute("appname"));
                    listViewParent->addWidget(view);
                    TQDomNode menuNode = topLevelNode.firstChild();
                    while(!menuNode.isNull()){
                        if(menuNode.isElement()){
                            TQDomElement elemNode=menuNode.toElement();
                            menuItemFromXML(view,lastChild(view),menuNode.toElement());
                        }
                        menuNode = menuNode.nextSibling();
                    }
                    listViews.append(view);
                }
            }
            topLevelNode = topLevelNode.nextSibling();
        }
    }
}

void Config::toKommandoMenu(Kommando* buttonParent)
{
    TQPtrList<Menu> topLevelMenus;
    Menu* defaultMenu = 0;
    if(doc){
        TQDomNode node = doc->documentElement().firstChild();

        while(!node.isNull()){
            if(node.isElement()&&(node.toElement().tagName() == "menu")){
                Menu* mainMenu = menuFromXML(node.toElement(),buttonParent);
                if((mainMenu->appName() == "default") || (mainMenu->appName() == TQString::null)){
                    defaultMenu = mainMenu;
                }
                mainMenu->arrangeButtons();
                topLevelMenus.append(mainMenu);
            }
            node = node.nextSibling();
        }
        for(Menu* it = topLevelMenus.first(); it != 0; it = topLevelMenus.next()){
            if(it != defaultMenu){
                SubmenuButton* button = new SubmenuButton(buttonParent,defaultMenu,mMenuButtonSize);
                button->hide();
                button->setIcon("go-up");
                //This registers the button with the Menu, but does not add it to its child List
                //Doing so would cause the menu to delete the default menu, which already deletes itsself
                it->insertNoChild(button);
                it->arrangeButtons();
            }
        }
        buttonParent->resize();
        buttonParent->setTopLevelMenus(topLevelMenus);
        buttonParent->setNavButtonSize(mNavButtonSize);
    }
}

void Config::setDefaultValues()
{
    setTintColor(TQt::black);
    setOpacity(0.2f);
    setShortcut("Alt+Ctrl+H");
    setNavButtonSize(32);
    setMenuButtonSize(32);
    setMenuRadius(132);
    setScheme("Normal");

    if(doc){
        delete doc;
    }
    doc = new TQDomDocument();
    TQDomElement root = doc->createElement("root");
    doc->appendChild(root);

    newNode("access",root,Shortcut(),"method","shortcut");
    newNode("menubuttonsize",root,32);
    newNode("navbuttonsize",root,32);
    newNode("tintcolor",root,"#000000");
    newNode("opacity",root,0.2f);
    newNode("menuradius",root,132);
    newNode("scheme",root,"Normal");

    TQDomElement node= newMenu(root,"default");
    newButton(node,"konsole","konsole --workdir $HOME");
    newButton(node,"kwrite","kwrite");
    newButton(node,"konqueror","konqueror");
    newButton(node,"kcalc","kcalc");
    newButton(node,"gimp","gimp");
    newButton(node,"kfm_home","kfmclient openProfile filemanagement");
    node = newMenu(node,TQString::null,"kmix");
    newButton(node,"kmix","kmix");
    newButton(node,"k3b","k3b");
    newButton(node,"amarok","amarok");
    newButton(node,"kaffeine","kaffeine");
}

Menu * Config::menuFromXML( const TQDomElement & ownNode, Kommando * buttonParent, Menu* parent)
{
    TQDomNode node=ownNode.firstChild();

    Menu* newMenu = new Menu(parent,ownNode.attribute("appname"));

    while(!node.isNull()){
        if(node.isElement()){
            RoundButton* button;
            if(node.nodeName() == "button"){
                button = comButtonFromXML(node.toElement(),buttonParent);
                newMenu->insert(button);
            } else if(node.nodeName()=="menu"){
                Menu* subMenu = menuFromXML(node.toElement(),buttonParent,newMenu);             //establish all necessary connections, e.g. menu structure
                button = new SubmenuButton(buttonParent,subMenu,mMenuButtonSize);
                newMenu->insert(button);
                button->setIcon(subMenu->IconPath());
            } else if(node.nodeName()=="icon"){
                newMenu->setIconPath(node.firstChild().nodeValue());
            }
        }
        node=node.nextSibling();
    }

    newMenu->hideButtons();

    return newMenu;
}

CommandoButton* Config::comButtonFromXML(const TQDomElement& ownNode, Kommando* parent)
{
    CommandoButton* button = new CommandoButton(parent,mMenuButtonSize);

    TQDomNode bnode=ownNode.firstChild();
    while (!bnode.isNull()){
        if(bnode.nodeName() == "command"){
            button->setCommand(bnode.firstChild().nodeValue());
        } else if (bnode.nodeName() == "icon"){
            button->setIcon(bnode.firstChild().nodeValue());
        }
        bnode=bnode.nextSibling();
    }
    return button;
}

TQDomElement Config::newNode( const TQString& nodename, TQDomNode& parent, int value )
{
    TQDomElement node=doc->createElement(nodename);
    node.appendChild(doc->createTextNode(TQString::number(value)));
    parent.appendChild(node);

    return node;
}

TQDomElement Config::newNode( const TQString& nodename, TQDomNode& parent, float value )
{
    TQDomElement node=doc->createElement(nodename);
    node.appendChild(doc->createTextNode(TQString::number(value)));
    parent.appendChild(node);

    return node;
}

TQDomElement Config::newNode( const TQString& nodename, TQDomNode& parent, const TQString& value )
{
    TQDomElement node=doc->createElement(nodename);
    node.appendChild(doc->createTextNode(value));
    parent.appendChild(node);

    return node;
}

TQDomElement Config::newNode( const TQString& nodename, TQDomNode& parent, const TQString& value, const TQString& attrname, const TQString& attrvalue )
{
    TQDomElement node=doc->createElement(nodename);
    node.setAttribute(attrname,attrvalue);
    node.appendChild(doc->createTextNode(value));
    parent.appendChild(node);

    return node;
}

TQDomElement Config::newButton(TQDomNode& parent, const TQString& icon, const TQString& command )
{
    TQDomElement root = doc->createElement("button");
    if(command!=""){
        TQDomElement node = doc->createElement("command");
        node.appendChild(doc->createTextNode(command));
        root.appendChild(node);
    }
    if(icon!=""){
        TQDomElement node=doc->createElement("icon");
        node.appendChild(doc->createTextNode(icon));
        root.appendChild(node);
    }
    parent.appendChild(root);
    return root;
}

TQDomElement Config::newMenu( TQDomNode & parent, const TQString& appName, const TQString& icon )
{
    TQDomElement root = doc->createElement("menu");
    if(appName != TQString::null){
        root.setAttribute("appname", appName);
    }
    if(icon != TQString::null){
        TQDomElement node=doc->createElement("icon");
        node.appendChild(doc->createTextNode(icon));
        root.appendChild(node);
    }
    parent.appendChild(root);
    return root;
}

void Config::menuItemToXML( TQDomNode & parent, MenuListViewItem* item)
{
    if(item->type()==MenuListViewItem::Menu){
     TQDomElement node = newMenu(parent,TQString::null,item->iconPath());
        TQListViewItem* temp = item->firstChild();
        while(temp){
            menuItemToXML(node,static_cast<MenuListViewItem*>(temp));
            temp=temp->nextSibling();
        }
    } else if(item->type()==MenuListViewItem::Button){
        newButton(parent,item->iconPath(),item->text(1));
    }
}

void Config::menuItemFromXML(KommandoView* parent, TQListViewItem* after, const TQDomElement& ownNode)
{
    MenuListViewItem* item;
    if (ownNode.tagName()=="menu"){
        item = new MenuListViewItem(parent,after,"Menu",MenuListViewItem::Menu);
        item->setOpen(true);
    } else if (ownNode.tagName()=="button"){
        item = new MenuListViewItem(parent,after,"Button",MenuListViewItem::Button);
    } else return;
    itemHelper(ownNode,item);   //Parse properties and children of this item
}

void Config::menuItemFromXML(TQListViewItem* parent, TQListViewItem* after, const TQDomElement& ownNode)
{
    MenuListViewItem* item;
    if (ownNode.tagName()=="menu"){
        item = new MenuListViewItem(parent,after,"Menu",MenuListViewItem::Menu);
        item->setOpen(true);
    } else if (ownNode.tagName()=="button"){
        item = new MenuListViewItem(parent,after,"Button",MenuListViewItem::Button);
    } else return;

    itemHelper(ownNode,item);  //Parse properties and children of this item
}

void Config::itemHelper(const TQDomElement& ownNode, MenuListViewItem* item)
{
    TQDomNode temp = ownNode.firstChild();

    while(!temp.isNull()){
        if(temp.isElement()){
            TQDomElement temp2=temp.toElement();
            if(temp2.tagName() == "icon"){
                item->setIconPath(temp2.firstChild().nodeValue());
            } else if((temp2.tagName() == "command") && (item->type() == MenuListViewItem::Button)){
                item->setText(1,temp2.firstChild().nodeValue());
            //is item a menu? otherwise parsing buttons and submenus would not make sense
            } else if(((temp2.tagName() == "menu") || (temp2.tagName() == "button")) && (item->type() == MenuListViewItem::Menu)){
                menuItemFromXML(item,item->lastChild(),temp2);
            }
        }
        temp=temp.nextSibling();
    }
}
