/////////////////////////////////////////////////////////////////////////////
// Author:      Vaclav Slavik
// Created:     2000/05/05
// RCS-ID:      $Id: nodehnd.cpp,v 1.10 2004/06/11 13:14:23 ABX Exp $
// Copyright:   (c) 2000 Vaclav Slavik
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "nodehnd.h"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include "nodehnd.h"
#include "wx/xml/xml.h"
#include "wx/filefn.h"
#include "wx/wx.h"
#include "wx/arrimpl.cpp"
#include "wx/textfile.h"
#include "wx/tokenzr.h"
#include "wx/listctrl.h"
#include "editor.h"
#include "treedt.h"
#include "xmlhelpr.h"
#include "nodesdb.h"



wxList NodeHandler::ms_Handlers;
bool NodeHandler::ms_HandlersLoaded = false;


NodeHandler *NodeHandler::Find(wxXmlNode *node)
{
    if (!ms_HandlersLoaded)
    {
        ms_HandlersLoaded = true;
        ms_Handlers.DeleteContents(true);

        NodeInfoArray& arr = NodesDb::Get()->GetNodesInfo();
        NodeHandler *hnd;
        for (size_t i = 0; i < arr.GetCount(); i++)
        {
            if (arr[i].NodeClass.IsEmpty() || arr[i].Abstract) continue;

                 if (arr[i].Type == _T("panel"))
                hnd = new NodeHandlerPanel(&(arr[i]));
            else if (arr[i].Type == _T("sizer"))
                hnd = new NodeHandlerSizer(&(arr[i]));
            else if (arr[i].Type == _T("sizeritem"))
                hnd = new NodeHandlerSizerItem(&(arr[i]));
            else if (arr[i].Type == _T("notebook"))
                hnd = new NodeHandlerNotebook(&(arr[i]));
            else if (arr[i].Type == _T("notebookpage"))
                hnd = new NodeHandlerNotebookPage(&(arr[i]));
            else
                hnd = new NodeHandler(&(arr[i]));
            if (hnd) ms_Handlers.Append(hnd);
        }
        ms_Handlers.Append(new NodeHandlerUnknown);
    }

    wxNode *n = ms_Handlers.GetFirst();
    while (n)
    {
        NodeHandler *h = (NodeHandler*) n->GetData();
        if (h->CanHandle(node))
            return h;
        n = n->GetNext();
    }
    return NULL;
}




NodeHandler::NodeHandler(NodeInfo *ni) :
        m_NodeInfo(ni)
{
}


NodeHandler::~NodeHandler()
{
}



bool NodeHandler::CanHandle(wxXmlNode *node)
{
    return (m_NodeInfo->NodeClass == XmlGetClass(node));
}




PropertyInfoArray& NodeHandler::GetPropsList(wxXmlNode *WXUNUSED(node))
{
    return m_NodeInfo->Props;
}



wxTreeItemId NodeHandler::CreateTreeNode(wxTreeCtrl *treectrl,
                                         wxTreeItemId parent,
                                         wxXmlNode *node)
{
    int icon = GetTreeIcon(node);
    wxTreeItemId item =
        treectrl->AppendItem(parent, GetTreeString(node),
                             icon, icon, new XmlTreeData(node));
    if (parent == treectrl->GetRootItem())
        treectrl->SetItemBold(item);
    return item;
}



wxString NodeHandler::GetTreeString(wxXmlNode *node)
{
    wxString xmlid = node->GetPropVal(_T("name"), wxEmptyString);
    if (xmlid.IsEmpty())
        return XmlGetClass(node);
    else
        return XmlGetClass(node) + _T(" '") + xmlid + _T("'");
}




wxArrayString& NodeHandler::GetChildTypes()
{
    if (m_ChildTypes.IsEmpty())
    {
        wxString basetype = m_NodeInfo->ChildType;
        NodeInfoArray& arr = NodesDb::Get()->GetNodesInfo();

        for (size_t i = 0; i < arr.GetCount(); i++)
        {
            NodeInfo &ni = arr[i];

            if (ni.NodeClass == basetype && !ni.Abstract)
                m_ChildTypes.Add(ni.NodeClass);

            if (ni.DerivedFrom.Index(basetype) != wxNOT_FOUND && !ni.Abstract)
                m_ChildTypes.Add(ni.NodeClass);
        }
        m_ChildTypes.Sort();
    }

    return m_ChildTypes;
}



void NodeHandler::InsertNode(wxXmlNode *WXUNUSED(parent), wxXmlNode *node, wxXmlNode *WXUNUSED(insert_before))
{
    delete node;
    wxLogError(_("Cannot insert child into this type of node!"));
}








wxTreeItemId NodeHandlerPanel::CreateTreeNode(wxTreeCtrl *treectrl,
                                         wxTreeItemId parent,
                                         wxXmlNode *node)
{
    wxTreeItemId root = NodeHandler::CreateTreeNode(treectrl, parent, node);

    wxXmlNode *n = XmlFindNode(node, _T("object"));

    while (n)
    {
        if (n->GetType() == wxXML_ELEMENT_NODE &&
            n->GetName() == _T("object"))
            Find(n)->CreateTreeNode(treectrl, root, n);
        n = n->GetNext();
    }
    //treectrl->Expand(root);
    return root;
}



void NodeHandlerPanel::InsertNode(wxXmlNode *parent, wxXmlNode *node, wxXmlNode *insert_before)
{
    if (insert_before)
        parent->InsertChild(node, insert_before);
    else
        parent->AddChild(node);
    EditorFrame::Get()->NotifyChanged(CHANGED_TREE);
}





void NodeHandlerSizer::InsertNode(wxXmlNode *parent, wxXmlNode *node, wxXmlNode *insert_before)
{
    if (XmlGetClass(node) == _T("spacer") || XmlGetClass(node) == _T("sizeritem"))
    {
        if (insert_before)
            parent->InsertChild(node, insert_before);
        else
            parent->AddChild(node);
    }
    else
    {
        wxXmlNode *itemnode = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
        itemnode->AddProperty(_T("class"), _T("sizeritem"));
        itemnode->AddChild(node);

        if (insert_before)
            parent->InsertChild(itemnode, insert_before);
        else
            parent->AddChild(itemnode);
    }
    EditorFrame::Get()->NotifyChanged(CHANGED_TREE);
}



int NodeHandlerSizer::GetTreeIcon(wxXmlNode *node)
{
    int orig = NodeHandler::GetTreeIcon(node);
    if (orig == 0)
    {
        if (XmlReadValue(node, _T("orient")) == _T("wxVERTICAL")) return 2;
        else return 3;
    }
    else return orig;
}



wxTreeItemId NodeHandlerSizerItem::CreateTreeNode(wxTreeCtrl *treectrl,
                                         wxTreeItemId parent,
                                         wxXmlNode *node)
{
    wxTreeItemId root;

    root = Find(GetRealNode(node))->CreateTreeNode(treectrl, parent, GetRealNode(node));
    ((XmlTreeData*)treectrl->GetItemData(root))->Node = node;

    //treectrl->Expand(root);
    return root;
}



PropertyInfoArray& NodeHandlerSizerItem::GetPropsList(wxXmlNode *node)
{
    m_dummy = NodeHandler::GetPropsList(node);
    wxXmlNode *nd = GetRealNode(node);
    m_dummy.Add(PropertyInfo(wxEmptyString, wxEmptyString, wxEmptyString));
    size_t pos = m_dummy.GetCount();
    WX_APPEND_ARRAY(m_dummy,
                    Find(nd)->GetPropsList(nd));
    for (size_t i = pos; i < m_dummy.GetCount(); i++)
        m_dummy[i].Name = _T("object/") + m_dummy[i].Name;

    return m_dummy;
}



wxString NodeHandlerSizerItem::GetTreeString(wxXmlNode *node)
{
    wxXmlNode *n = GetRealNode(node);
    return Find(n)->GetTreeString(n);
}



int NodeHandlerSizerItem::GetTreeIcon(wxXmlNode *node)
{
    wxXmlNode *n = GetRealNode(node);
    return Find(n)->GetTreeIcon(n);
}



wxXmlNode *NodeHandlerSizerItem::GetRealNode(wxXmlNode *node)
{
    return XmlFindNode(node, _T("object"));
}






void NodeHandlerNotebook::InsertNode(wxXmlNode *parent, wxXmlNode *node, wxXmlNode *insert_before)
{
    {
        wxXmlNode *itemnode;

        if (XmlGetClass(node) == _T("notebookpage"))
            itemnode = node;
        else
        {
            itemnode = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
            itemnode->AddProperty(_T("class"), _T("notebookpage"));
            itemnode->AddChild(node);
        }

        if (insert_before)
            parent->InsertChild(itemnode, insert_before);
        else
            parent->AddChild(itemnode);
    }
    EditorFrame::Get()->NotifyChanged(CHANGED_TREE);
}
