/***************************************************************
 * Name:      wxsmith.cpp
 * Purpose:   Code::Blocks plugin
 * Author:    BYO<byo.spoon@gmail.com>
 * Created:   04/10/05 01:05:08
 * Copyright: (c) BYO
 * License:   GPL
 **************************************************************/

#include "wxsheaders.h"
#include <licenses.h>
#include <manager.h>
#include <tinyxml/tinyxml.h>
#include <messagemanager.h>
#include <cbeditor.h>
#include <projectmanager.h>
#include <wx/notebook.h>
#include <wx/sashwin.h>
#include <configmanager.h>

#include "wxsmith.h"
#include "wxswindoweditor.h"
#include "defwidgets/wxsstdmanager.h"
#include "wxscodegen.h"
#include "wxspropertiesman.h"
#include "wxsproject.h"
#include "wxswidgetfactory.h"
#include "wxspalette.h"
#include "wxsevent.h"
#include "wxsnewwindowdlg.h"
#include "wxsimportxrcdlg.h"
#include "wxsresourcetree.h"
#include "wxssettingsdlg.h"

static int NewDialogId = wxNewId();
static int NewFrameId = wxNewId();
static int NewPanelId = wxNewId();
static int ImportXrcId = wxNewId();

CB_IMPLEMENT_PLUGIN(wxSmith);

wxSmith* wxSmith::Singleton = NULL;

BEGIN_EVENT_TABLE(wxSmith, cbPlugin)
	EVT_PROJECT_CLOSE(wxSmith::OnProjectClose)
	EVT_PROJECT_OPEN(wxSmith::OnProjectOpen)
	EVT_PROJECT_ACTIVATE(wxSmith::OnProjectActivated)
	EVT_SELECT_RES(wxSmith::OnSpreadEvent)
	EVT_UNSELECT_RES(wxSmith::OnSpreadEvent)
	EVT_SELECT_WIDGET(wxSmith::OnSpreadEvent)
	EVT_UNSELECT_WIDGET(wxSmith::OnSpreadEvent)
	EVT_MENU(NewDialogId,wxSmith::OnNewWindow)
	EVT_MENU(NewFrameId,wxSmith::OnNewWindow)
	EVT_MENU(NewPanelId,wxSmith::OnNewWindow)
	EVT_MENU(ImportXrcId,wxSmith::OnImportXrc)
END_EVENT_TABLE()

wxSmith::wxSmith()
{
	//ctor
	m_PluginInfo.name = _("wxSmith");
	m_PluginInfo.title = _("wxSmith");
	m_PluginInfo.version = _("1.0");
	m_PluginInfo.description = _("RAD tool used to create wxWidgets forms");
	m_PluginInfo.author = _("BYO");
	m_PluginInfo.authorEmail = _("byo.spoon@gmail.com");
	m_PluginInfo.authorWebsite = _("");
	m_PluginInfo.thanksTo = _("Ann for Being\nGigi for Faworki\n\nGod for Love\n\nJaakko Salli for wxPropertyGrid");
	m_PluginInfo.license = LICENSE_GPL;
	m_PluginInfo.hasConfigure = true;

	if ( Singleton == NULL ) Singleton = this;
}

wxSmith::~wxSmith()
{
	if ( Singleton == this ) Singleton = NULL;
}

void wxSmith::OnAttach()
{
    ConfigManager::AddConfiguration(m_PluginInfo.title, _T("/wxsmith"));     wxNotebook* Notebook = Manager::Get()->GetNotebook();
	if ( Notebook )
	{
        // Creating main splitting objects

        LeftSplitter = new wxsSplitterWindowEx(Notebook);
        Notebook->AddPage(LeftSplitter,_("Resources"));

        wxPanel* ResourcesContainer = new wxPanel(LeftSplitter->GetSplitter(),-1,wxDefaultPosition,wxDefaultSize,0);
        wxPanel* PropertiesContainer = new wxPanel(LeftSplitter->GetSplitter(),-1,wxDefaultPosition,wxDefaultSize,0);

        // Adding resource browser

        wxSizer* Sizer = new wxGridSizer(1);
        ResourceBrowser = new wxsResourceTree(ResourcesContainer);
        ResourceBrowser->Expand(ResourceBrowser->AddRoot(_("Resources")));
        Sizer->Add(ResourceBrowser,1,wxGROW|wxALL);
        ResourcesContainer->SetSizer(Sizer);

        // Adding new page into Manager
        Sizer = new wxGridSizer(1);
        wxNotebook* LDNotebook = new wxNotebook(PropertiesContainer,-1,wxDefaultPosition,wxDefaultSize,wxSUNKEN_BORDER);
        PropertiesPanel = new wxScrolledWindow(LDNotebook);
        PropertiesPanel->SetScrollRate(5,5);
        EventsPanel = new wxScrolledWindow(LDNotebook);
        EventsPanel->SetScrollRate(5,5);
        LDNotebook->AddPage(PropertiesPanel,_("Properties"));
        LDNotebook->AddPage(EventsPanel,_("Events"));
        Sizer->Add(LDNotebook,1,wxGROW);
        PropertiesContainer->SetSizer(Sizer);

        wxsPropertiesMan::Get()->PropertiesPanel = PropertiesPanel;
        wxsPropertiesMan::Get()->EventsPanel = EventsPanel;

        LeftSplitter->Split(ResourcesContainer,PropertiesContainer);

        MessageManager* Messages = Manager::Get()->GetMessageManager();
        Manager::Get()->Loadxrc(_T("/wxsmith.zip#zip:*"));

        // Initializing standard manager

        wxsStdManager.Initialize();

        if ( ! wxsStdManager.RegisterInFactory() )
        {
            //DebLog("Couldn't register standard widget's factory - this plugin will be useless");
        }
        // TODO (SpOoN#1#): Add other widgets

        if ( Messages )
        {
            // Creating widgets palette ad the messages Notebook
            wxWindow* Palette = new wxsPalette((wxWindow*)Messages,Messages->GetPageCount());
            Messages->AddPage(Palette,_("Widgets"));
        }
	}
	else
	{
        LeftSplitter = NULL;
        PropertiesPanel = NULL;
        EventsPanel = NULL;
        ResourceBrowser = NULL;
	}

}

void wxSmith::OnRelease(bool appShutDown)
{
    for ( ProjectMapI i = ProjectMap.begin(); i!=ProjectMap.end(); ++i )
    {
        if ( (*i).second )
        {
            delete (*i).second;
            (*i).second = NULL;
        }
    }

    ProjectMap.clear();
}

int wxSmith::Configure()
{
	wxsSettingsDlg Dlg(NULL);
	Dlg.ShowModal();
	return 0;
}

void wxSmith::BuildMenu(wxMenuBar* menuBar)
{
	wxMenu* Menu = new wxMenu;
	Menu->Append(NewDialogId,_("Add Dialog"));
	Menu->Append(NewFrameId,_("Add Frame"));
	Menu->Append(NewPanelId,_("Add Panel"));
	Menu->AppendSeparator();
	Menu->Append(ImportXrcId,_("Import XRC file"));

	int ToolsPos = menuBar->FindMenu(_("&Tools"));

	if  ( ToolsPos == wxNOT_FOUND )
	{
        menuBar->Append(Menu,_("wxSmith"));
	}
	else
	{
        menuBar->Insert(ToolsPos,Menu,_("wxSmith"));
	}
}

void wxSmith::BuildModuleMenu(const ModuleType type, wxMenu* menu, const wxString& arg)
{
}

bool wxSmith::BuildToolBar(wxToolBar* toolBar)
{
	return false;
}

void wxSmith::OnProjectClose(CodeBlocksEvent& event)
{
    cbProject* Proj = event.GetProject();
    ProjectMapI i = ProjectMap.find(Proj);
    if ( i == ProjectMap.end() ) return;

    wxsProject* SmithProj = (*i).second;
    ProjectMap.erase(i);
    if ( SmithProj )
    {
        SmithProj->SaveProject();
        delete SmithProj;
    }

    event.Skip();
}

void wxSmith::OnProjectOpen(CodeBlocksEvent& event)
{
    wxsProject* NewProj = new wxsProject;
    NewProj->BindProject(event.GetProject());
    ProjectMap[event.GetProject()] = NewProj;
    event.Skip();
}

void wxSmith::OnProjectActivated(CodeBlocksEvent& event)
{
    event.Skip();
}

void wxSmith::OnSpreadEvent(wxsEvent& event)
{
    wxsPropertiesMan::Get()->ProcessEvent(event);
    for ( ProjectMapI i = ProjectMap.begin(); i != ProjectMap.end(); ++i )
    {
    	(*i).second->SendEventToEditors(event);
    }
    wxsPalette::Get()->ProcessEvent(event);
}

cbProject* wxSmith::GetCBProject(wxsProject* Proj)
{
    return Proj->GetCBProject();
}

wxsProject* wxSmith::GetSmithProject(cbProject* Proj)
{
    ProjectMapI i = ProjectMap.find(Proj);

    if ( i == ProjectMap.end() ) return NULL;

    return (*i).second;
}

void wxSmith::OnNewWindow(wxCommandEvent& event)
{
    if ( !CheckIntegration() ) return;

    wxString ResType = _T("Dialog");

    if ( event.GetId() == NewDialogId )      ResType = _T("Dialog");
    else if ( event.GetId() == NewFrameId  ) ResType = _T("Frame");
    else if ( event.GetId() == NewPanelId  ) ResType = _T("Panel");
    else
    {
    	wxMessageBox(_("Internal error - invalid resource type"));
    	return;
    }

    wxsNewWindowDlg Dlg(Manager::Get()->GetAppWindow(),ResType);
    Dlg.ShowModal();
}

void wxSmith::OnImportXrc(wxCommandEvent& event)
{
    if ( !CheckIntegration() ) return;

	wxString FileName = ::wxFileSelector(
        _("Select XRC file"),
        _T(""),
        _T(""),
        _T("xrc"),
        _("XRC files (*.xrc)|*.xrc"),
        wxOPEN|wxFILE_MUST_EXIST);

    if ( FileName.empty() ) return;

    // Loading xrc file into xml document

    TiXmlDocument Doc(FileName.mb_str());
    TiXmlElement* Resource;     if (! Doc.LoadFile() ||
        ! (Resource = Doc.FirstChildElement("resource")) )
    {
    	wxMessageBox(_("Couldn't load XRC file."));
        return;
    }     // Generating list of objects
    wxArrayString Resources;     TiXmlElement* Element = Resource->FirstChildElement("object");     while ( Element )
    {
    	const char* Class = Element->Attribute("class");
    	const char* Name = Element->Attribute("name");
    	if ( !Class || !Name ) continue;

    	if ( !strcmp(Class,"wxDialog") ||
    	     !strcmp(Class,"wxPanel") ||
    	     !strcmp(Class,"wxFrame") )
        {
        	Resources.Add(wxString(Name,wxConvUTF8));
        }

        Element = Element->NextSiblingElement("object");
    }

    if ( Resources.Count() == 0 )
    {
    	wxMessageBox(_("Didn't find any editable resources"));
    	return;
    }

    // Selecting resource to edit

    wxString Name;

    if ( Resources.Count() == 1 )
    {
    	Name = Resources[0];
    }
    else
    {
        int Index = ::wxGetSingleChoiceIndex(
            _("Select resource to import"),
            _("Importing XRC"),
            Resources );
        if ( Index == -1 ) return;
        Name = Resources[Index];
    }

    Element = Resource->FirstChildElement("object");
    while ( Element )
    {
        if ( !strcmp(Element->Attribute("name"),Name.mb_str()) )
        {
            break;
        }
        Element = Element->NextSiblingElement("object");
    }     if ( !Element ) return;

    // Creating fake resource and testing if xrc can be loaded without any errors
    wxsWidget* Test = wxsGEN(wxString(Element->Attribute("class"),wxConvUTF8),NULL);
    if ( !Test )
    {
    	// Something went wrong - default factory is not working ?
    	wxMessageBox(_("Internal error"));
    	return;
    }

    if ( !Test->XmlLoad(Element) )
    {
		if ( wxMessageBox(_("Resource was not loaded properly. Some widgets may be\n"
                            "damaged or will be removed. Continue ?"),
                          _("XRC Load error"),
                          wxYES_NO|wxICON_QUESTION) == wxNO )
        {
        	delete Test;
        	return;
        }
    }
    delete Test;

    // Displaying configuration dialog - it will handle adding resource to project
    wxsImportXrcDlg Dlg(Manager::Get()->GetAppWindow(),Element);
    Dlg.ShowModal();
}

bool wxSmith::CheckIntegration()
{
    cbProject* Project = Manager::Get()->GetProjectManager()->GetActiveProject();

    if ( !Project )
    {
        wxMessageBox(_("Please open project first"),_("Error"),wxOK|wxICON_ERROR);
        return false;
    }

    wxsProject* Proj = GetSmithProject(Project);

    if ( !Proj )
    {
        DebLog(_("Something wrong - couldn't find assciated wxsProject"));
        return false;
    }

    switch ( Proj->GetIntegration() )
    {
        case wxsProject::NotBinded:
            return false;

        case wxsProject::NotWxsProject:
            if ( wxMessageBox(_("Active project doesn't use wxSmith.\nShould I change it ?"),
                              _("Not wxSmith project"),wxYES_NO|wxICON_EXCLAMATION ) == wxYES )
            {
                if ( !Proj->AddSmithConfig() ) return false;
            }
            else
            {
                return false;
            }
            break;

        default:
            break;
    }

    return true;
}



syntax highlighted by Code2HTML, v. 0.9.1