/***************************************************************************
 *   Copyright (C) 2001 by Bernd Gehrmann                                  *
 *   bernd@kdevelop.org                                                    *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "hierarchydlg.h"

#include <kdialog.h>
#include <tdelocale.h>
#include <kpushbutton.h>
#include <kstdguiitem.h>
#include <tdefile.h>
#include <tdefiledialog.h>
#include <kurlrequesterdlg.h>
#include <kurlrequester.h>
#include <tdemessagebox.h>
#include <kdebug.h>

#include <tqlayout.h>
#include <tqfileinfo.h>
#include <tqlistview.h>
#include <tqapplication.h>
#include <tqsplitter.h>

#include "kdevlanguagesupport.h"
#include "kcomboview.h"

#include "classviewpart.h"
//#include "classtoolwidget.h"
#include "digraphview.h"
#include "viewcombos.h"


HierarchyDialog::HierarchyDialog( ClassViewPart *part )
    : TQDialog(0, "hierarchy dialog", false)
{
    class_combo = new KComboView(true, 150, this);
    class_combo->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Preferred );
//    class_combo->setMinimumWidth(150);
    namespace_combo = new KComboView(true, 150, this);
    namespace_combo->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Preferred );
//    namespace_combo->setMinimumWidth(150);

    TQPushButton *close_button = new KPushButton(KStdGuiItem::close(), this);
    TQPushButton *save_button = new KPushButton(KStdGuiItem::save(), this);
    TQPushButton *refresh_button = new KPushButton(i18n("Refresh"), this);

    TQSplitter *splitter = new TQSplitter(Qt::Vertical, this);
    digraph = new DigraphView(splitter, "digraph view");
//    member_tree = new ClassToolWidget(part, splitter);

    TQBoxLayout *layout = new TQVBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint());
    TQBoxLayout *combo_layout = new TQHBoxLayout();
    layout->addLayout(combo_layout);
    combo_layout->addWidget(namespace_combo);
    combo_layout->addWidget(class_combo);
    combo_layout->addSpacing(60);
    combo_layout->addWidget(refresh_button);
    combo_layout->addWidget(save_button);
    combo_layout->addWidget(close_button);
    layout->addWidget(splitter);

    connect( namespace_combo, TQT_SIGNAL(activated(TQListViewItem*)),
             this, TQT_SLOT(slotNamespaceComboChoice(TQListViewItem*)) );
    connect( class_combo, TQT_SIGNAL(activated(TQListViewItem*)),
             this, TQT_SLOT(slotClassComboChoice(TQListViewItem*)) );
    connect( namespace_combo, TQT_SIGNAL(textChanged(const TQString&)),
             this, TQT_SLOT(slotNamespaceComboChoice(const TQString&)) );
    connect( class_combo, TQT_SIGNAL(textChanged(const TQString&)),
             this, TQT_SLOT(slotClassComboChoice(const TQString&)) );
    connect( close_button, TQT_SIGNAL(clicked()),
             this, TQT_SLOT(hide()) );
    connect( save_button, TQT_SIGNAL(clicked()),
             this, TQT_SLOT(save()) );
    connect( refresh_button, TQT_SIGNAL(clicked()),
             this, TQT_SLOT(refresh()) );
    connect( digraph, TQT_SIGNAL(selected(const TQString&)),
             this, TQT_SLOT(classSelected(const TQString&)) );

    m_part = part;
//    m_part->registerHierarchyDialog(this);
    refresh();
}


HierarchyDialog::~HierarchyDialog()
{
//    m_part->unregisterHierarchyDialog(this);
}

void HierarchyDialog::save()
{
    KURLRequesterDlg dlg(TQString(), this, "save_inheritance");
    dlg.fileDialog()->setFilter("image/png image/jpeg image/bmp image/svg+xml");
    dlg.fileDialog()->setOperationMode( KFileDialog::Saving );
    dlg.fileDialog()->setMode( KFile::File | KFile::LocalOnly );
    dlg.urlRequester()->setMode( KFile::File | KFile::LocalOnly );
    if(dlg.exec() && dlg.selectedURL().isLocalFile())
    {
	TQFileInfo fi(dlg.selectedURL().pathOrURL());
        TQApplication::setOverrideCursor( TQt::waitCursor );
        KDevLanguageSupport *ls = m_part->languageSupport();
        for (TQMap<TQString, ClassDom>::const_iterator it = classes.begin(); it != classes.end(); ++it)
        {
            kdDebug(9003) << "Adding class to graph: " << it.key() << endl;
            TQString formattedName = ls->formatClassName(it.key());
            TQStringList baseClasses = it.data()->baseClassList();
            for (TQStringList::const_iterator bit = baseClasses.begin(); bit != baseClasses.end(); ++bit)
            {
                TQMap<TQString, TQString>::const_iterator baseIt = uclasses.find(*bit);
                if (baseIt != uclasses.end())
                {
                    TQString formattedParentName = ls->formatClassName(baseIt.data());
                    digraph->addEdge(formattedParentName, formattedName);
                }
            }
        }
        digraph->process(fi.absFilePath(), fi.extension());
        TQApplication::restoreOverrideCursor();
    }
}

void HierarchyDialog::refresh()
{
    digraph->clear();
    classes.clear();
    uclasses.clear();
    ViewCombosOp::refreshNamespaces(m_part, namespace_combo);
    processNamespace("", m_part->codeModel()->globalNamespace());

    KDevLanguageSupport *ls = m_part->languageSupport();

    for (TQMap<TQString, ClassDom>::const_iterator it = classes.begin(); it != classes.end(); ++it)
    {
        kdDebug(9003) << "Adding class to graph: " << it.key() << endl;
        TQString formattedName = ls->formatClassName(it.key());
        TQStringList baseClasses = it.data()->baseClassList();
        for (TQStringList::const_iterator bit = baseClasses.begin(); bit != baseClasses.end(); ++bit)
        {
            TQMap<TQString, TQString>::const_iterator baseIt = uclasses.find(*bit);
            if (baseIt != uclasses.end())
            {
                TQString formattedParentName = ls->formatClassName(baseIt.data());
                digraph->addEdge(formattedParentName, formattedName);
            }
        }
    }
    digraph->process();
}

void HierarchyDialog::setLanguageSupport(KDevLanguageSupport *ls)
{
    if (ls)
        connect(ls, TQT_SIGNAL(updatedSourceInfo()), this, TQT_SLOT(refresh()));
    else
        refresh();
}


void HierarchyDialog::slotClassComboChoice(TQListViewItem * item)
{
    ClassItem *ci = dynamic_cast<ClassItem*>(item);
    if (!ci)
        return;

    KDevLanguageSupport *ls = m_part->languageSupport();

    TQString className = ls->formatClassName(uclasses[item->text(0)]);
    digraph->setSelected(className);
    digraph->ensureVisible(className);
    classSelected(className);
}

void HierarchyDialog::slotClassComboChoice( const TQString& itemText )
{
    TQListViewItem* item = class_combo->listView()->firstChild();
    while( item )
    {
        if( item->text(0) == itemText )
	{
            ClassItem *ci = dynamic_cast<ClassItem*>(item);
            if (!ci)
                return;
        
            KDevLanguageSupport *ls = m_part->languageSupport();
        
            TQString className = ls->formatClassName(uclasses[item->text(0)]);
            digraph->setSelected(className);
            digraph->ensureVisible(className);
            classSelected(className);
      	    return;
	}
	item = item->nextSibling();
    }
}

void HierarchyDialog::classSelected(const TQString &/*className*/)
{
/*    ParsedClass *currentClass = m_part->classStore()->getClassByName(className);
    member_tree->clear();
    if (currentClass) {
        KDevLanguageSupport::Features features = m_part->languageSupport()->features();
        if (features & KDevLanguageSupport::Functions)
            member_tree->insertAllClassMethods(currentClass, (PIAccess)-1);
        if (features & KDevLanguageSupport::Variables)
            member_tree->insertAllClassAttributes(currentClass, (PIAccess)-1);
    }*/
}

void HierarchyDialog::slotNamespaceComboChoice( TQListViewItem * item )
{
    NamespaceItem *ni = dynamic_cast<NamespaceItem*>(item);
    if (!ni)
        return;
    ViewCombosOp::refreshClasses(m_part, class_combo, ni->dom()->name());
}

void HierarchyDialog::slotNamespaceComboChoice( const TQString& itemText )
{
    TQListViewItem* item = namespace_combo->listView()->firstChild();
    while( item )
    {
        if( item->text(0) == itemText )
	{
            NamespaceItem *ni = dynamic_cast<NamespaceItem*>(item);
            if (!ni)
                return;
            ViewCombosOp::refreshClasses(m_part, class_combo, ni->dom()->name());
	    return;
	}
	item = item->nextSibling();
    }
}

void HierarchyDialog::processNamespace( TQString prefix, NamespaceDom dom )
{
    tqWarning("processNamespace: prefix %s", prefix.latin1());
    TQString prefixInc = prefix.isEmpty() ? "" : ".";
//    TQString nsprefix = dom->name().isEmpty() ? TQString("") : prefixInc + dom->name();

    NamespaceList namespaceList = dom->namespaceList();
    for (NamespaceList::const_iterator it = namespaceList.begin(); it != namespaceList.end(); ++it)
    {
        tqWarning("about to processNamespace: prefix %s", (prefixInc + (*it)->name()).latin1());
        processNamespace(prefixInc + (*it)->name(), *it);
    }

    ClassList classList = dom->classList();
    for (ClassList::const_iterator it = classList.begin(); it != classList.end(); ++it)
    {
        processClass(prefix, *it);
    }
}

void HierarchyDialog::processClass( TQString prefix, ClassDom dom )
{
    tqWarning("processClass: prefix %s class %s", prefix.latin1(), dom->name().latin1());

    TQString prefixInc = prefix.isEmpty() ? "" : ".";
    classes[prefix + prefixInc + dom->name()] = dom;
    uclasses[dom->name()] = prefix + prefixInc + dom->name();

    ClassList classList = dom->classList();
    for (ClassList::const_iterator it = classList.begin(); it != classList.end(); ++it)
    {
        processClass(prefix + prefixInc + dom->name(), *it);
    }
}

#include "hierarchydlg.moc"