#include "wxsheaders.h"
#include "wxspalette.h"

#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/scrolwin.h>
#include <wx/statline.h>
#include <map>
#include "widget.h"
#include "wxswidgetfactory.h"
#include "wxspropertiesman.h"
#include "wxsmith.h"
#include "wxsresource.h"

static const int DeleteId = wxNewId();
static const int PreviewId = wxNewId();

wxsPalette* wxsPalette::Singleton = NULL;

wxsPalette::wxsPalette(wxWindow* Parent,int PN):
    wxPanel(Parent),
    SelectedRes(NULL),
    SelectedWidget(NULL),
    InsType(itBefore),
    InsTypeMask(0),
    PageNum(PN)
{
	wxScrolledWindow* Scroll = new wxScrolledWindow(this,-1);
	Scroll->SetScrollRate(5,5);

	wxFlexGridSizer* Sizer = new wxFlexGridSizer(0,1,5,5);
	Sizer->AddGrowableCol(0);
	Sizer->AddGrowableRow(1);

	wxFlexGridSizer* Sizer2 = new wxFlexGridSizer(2,0,5,15);
	Sizer2->AddGrowableCol(3);

	Sizer2->Add(new wxStaticText(Scroll,-1,_("Insertion type")));
	Sizer2->Add(new wxStaticText(Scroll,-1,_("Delete")));
	Sizer2->Add(new wxStaticText(Scroll,-1,_("Preview")));
	Sizer2->Add(new wxStaticText(Scroll,-1,_("Top list")));

	wxGridSizer* Sizer3 = new wxGridSizer(1,0,5,5);
	Sizer3->Add(AddBefore = new wxRadioButton(Scroll,-1,_("Before")));
	Sizer3->Add(AddAfter  = new wxRadioButton(Scroll,-1,_("After")));
	Sizer3->Add(AddInto   = new wxRadioButton(Scroll,-1,_("Into")));

	Sizer2->Add(Sizer3);

	Sizer2->Add(new wxButton(Scroll,DeleteId,_("Delete")));
	Sizer2->Add(new wxButton(Scroll,PreviewId,_("Preview")));

	Sizer->Add(Sizer2,0,wxALL|wxGROW,10);

	wxPanel* WidgetsSpace = new wxPanel(Scroll,-1);

	CreateWidgetsPalette(WidgetsSpace);

	Sizer->Add(WidgetsSpace,0,wxALL|wxGROW,10);

	Scroll->SetSizer(Sizer);
	Sizer->SetVirtualSizeHints(Scroll);

	wxSizer* TopSizer = new wxBoxSizer(wxVERTICAL);

	TopSizer->Add(Scroll,1,wxGROW);
	SetSizer(TopSizer);

	Singleton = this;

	SetInsertionTypeMask(0);

	SelectedRes = NULL;
	FindWindow(PreviewId)->Disable();

	Timer.SetOwner(this);

	Timer.Start(100,false);
}

wxsPalette::~wxsPalette()
{
	//dtor
}

int wxsPalette::GetInsertionType()
{
    int IT = InsType & InsTypeMask;

    if ( !IT )
    {
        if ( InsTypeMask & itBefore ) IT = itBefore;
        else if ( InsTypeMask & itAfter ) IT = itAfter;
        else if ( InsTypeMask & itInto ) IT = itInto;
    }

    return IT;
}

void wxsPalette::SetInsertionTypeMask(int Mask)
{
    InsTypeMask = Mask;

    AddBefore->Enable( (Mask & itBefore) != 0 );
    AddAfter->Enable( (Mask & itAfter) != 0 );
    AddInto->Enable( (Mask & itInto) != 0 );

    int CurrentIT = GetInsertionType();

    AddBefore->SetValue( (CurrentIT & itBefore) != 0 );
    AddAfter->SetValue( (CurrentIT & itAfter) != 0 );
    AddInto->SetValue( (CurrentIT & itInto) != 0 );
}

void wxsPalette::OnRadio(wxCommandEvent& event)
{
    int CurrentIT =
        ( AddBefore->GetValue() ? itBefore : 0 ) |
        ( AddAfter->GetValue()  ? itAfter  : 0 ) |
        ( AddInto->GetValue()   ? itInto   : 0 );

    InsType = CurrentIT;
}

namespace {
struct ltstr {  bool operator()(const wxChar* s1, const wxChar* s2) const { return wxStricmp(s1, s2) < 0; } };
};

void wxsPalette::CreateWidgetsPalette(wxWindow* Wnd)
{
    // First we need to split all widgets into groups
    // it will be done using multimap


    typedef std::multimap<const wxChar*,const wxsWidgetInfo*,ltstr> MapT;
    typedef MapT::iterator MapI;

    MapT Map;

    for ( const wxsWidgetInfo* Info = wxsFACTORY()->GetFirstInfo(); Info; Info = wxsFACTORY()->GetNextInfo() )
        Map.insert(std::pair<const wxChar*,const wxsWidgetInfo*>(Info->Category,Info));

    // Creatign main sizer inside window
    wxFlexGridSizer* Sizer = new wxFlexGridSizer(0,1,0,0);
    Sizer->AddGrowableCol(0);

    wxFlexGridSizer* RowSizer = NULL;

    const wxChar* PreviousGroup = _T("");

    for ( MapI i = Map.begin(); i != Map.end(); ++i )
    {
        if ( !(*i).first || wxStricmp(PreviousGroup,(*i).first) )
        {
            if ( RowSizer ) Sizer->Add(RowSizer,0,wxALL|wxGROW,5);
            Sizer->Add(new wxStaticLine(Wnd,-1),0,wxGROW);

            if ( (*i).first && (*i).first[0] )
            {
                // Need to create new group
                RowSizer = new wxFlexGridSizer(1,0,5,0);
                RowSizer->Add(new wxStaticText(Wnd,-1,(*i).first),0,wxALIGN_CENTER|wxALL,5);
                PreviousGroup = (*i).first;
            }
            else
            {
                RowSizer = NULL;
            }
        }

        if ( RowSizer )
        {
            if ( (*i).second->Icon )
            {
                wxBitmapButton* Btn =
                    new wxBitmapButton(Wnd,-1,*(*i).second->Icon,
                        wxDefaultPosition,wxDefaultSize,wxBU_AUTODRAW,
                        wxDefaultValidator, (*i).second->Name);
                RowSizer->Add(Btn,0,wxGROW);
                Btn->SetToolTip((*i).second->Name);
            }
            else
            {
                wxButton* Btn = new wxButton(Wnd,-1,(*i).second->Name,
                    wxDefaultPosition,wxDefaultSize,0,
                    wxDefaultValidator,(*i).second->Name);
                RowSizer->Add(Btn,0,wxGROW);
                Btn->SetToolTip((*i).second->Name);
            }
        }
    }

    if ( RowSizer ) Sizer->Add(RowSizer,0,wxALL|wxGROW,5);

    Wnd->SetSizer(Sizer);
    Sizer->SetSizeHints(Wnd);
}

void wxsPalette::OnButton(wxCommandEvent& event)
{
    wxWindowID Id = event.GetId();
    if ( Id == DeleteId )
    {
        DeleteRequest();
    }
    else if ( Id == PreviewId )
    {
        PreviewRequest();
    }
    else
    {
        wxWindow* Btn = (wxWindow*)event.GetEventObject();
        if ( Btn )
        {
            InsertRequest(Btn->GetName());
        }
    }
}

void wxsPalette::InsertRequest(const wxString& Name)
{
    wxsWidget* Current = wxsPropertiesMan::Get()->GetActiveWidget();
    if ( Current == NULL )
    {
        DebLog(_("wxSmith: No widget selected - couldn't create new widget"));
        return;
    }

    if ( !GetInsertionType() )
    {
        return;
    }

    wxsWindowEditor* Edit = Current->GetEditor();

    wxsWidget* NewWidget = wxsGEN(Name,Current->GetResource());
    if ( NewWidget == NULL )
    {
        DebLog(_("wxSmith: Culdn't generate widget inside factory"));
        return;
    }

    switch ( GetInsertionType() )
    {
        case itBefore:
            InsertBefore(NewWidget,Current);
            break;

        case itAfter:
            InsertAfter(NewWidget,Current);
            break;

        case itInto:
            InsertInto(NewWidget,Current);
            break;

        default:
            wxsKILL(NewWidget);
            DebLog(_("Something went wrong"));
            break;
    }


    if ( Edit )
    {
        Edit->BuildPreview();
    }

    if ( SelectedRes )
    {
		SelectedRes->NotifyChange();
    }
}

void wxsPalette::InsertBefore(wxsWidget* New,wxsWidget* Ref)
{
    wxsWidget* Parent = Ref->GetParent();

    int Index;

    if ( !Parent || (Index=Parent->FindChild(Ref)) < 0 || Parent->AddChild(New,Index) < 0 )
    {
        wxsKILL(New);
        return;
    }

    // Adding this new item into resource tree

    New->BuildTree(wxsTREE(),Parent->TreeId,Index);
    wxsTREE()->Refresh();
}

void wxsPalette::InsertAfter(wxsWidget* New,wxsWidget* Ref)
{
    wxsWidget* Parent = Ref->GetParent();

    int Index;

    if ( !Parent || (Index=Parent->FindChild(Ref)) < 0 || Parent->AddChild(New,Index+1) < 0 )
    {
        wxsKILL(New);
        return;
    }
    New->BuildTree(wxsTREE(),Parent->TreeId,Index+1);
    wxsTREE()->Refresh();
}

void wxsPalette::InsertInto(wxsWidget* New,wxsWidget* Ref)
{
    if ( Ref->AddChild(New) < 0 )
    {
        wxsKILL(New);
        return;
    }
    New->BuildTree(wxsTREE(),Ref->TreeId);
    wxsTREE()->Refresh();
}

void wxsPalette::DeleteRequest()
{

    wxsWidget* Current = wxsPropertiesMan::Get()->GetActiveWidget();
    if ( Current == NULL )
    {
        DebLog(_("wxSmith: No widget selecteed - couldn't delete"));
        return;
    }

    wxsWidget* Parent = Current->GetParent();

    if ( !Parent )
    {
        wxMessageBox(_("Can not delete main widget (for now ;)"));
        return;
    }

    wxsWindowEditor* Edit = Current->GetEditor();

    if ( Edit )
    {
        Edit->KillPreview();
    }

    wxsKILL(Current);

    if ( Edit )
    {
        Edit->BuildPreview();
    }

    if ( SelectedRes )
    {
		SelectedRes->NotifyChange();
    }
    wxsTREE()->Refresh();
}

void wxsPalette::PreviewRequest()
{
    if ( SelectedRes ) SelectedRes->ShowPreview();
}

void wxsPalette::OnSelectWidget(wxsEvent& event)
{
    int itMask = 0;

    if ( event.GetWidget()->GetParent() &&
         ( !event.GetWidget()->GetInfo().Sizer ||
            event.GetWidget()->GetParent()->GetInfo().Sizer ) )
    {
        itMask |= wxsPalette::itBefore | wxsPalette::itAfter;
    }

    if ( event.GetWidget()->IsContainer() )
    {
        itMask |= wxsPalette::itInto;
    }

    SetInsertionTypeMask(itMask);
    SelectedWidget = event.GetWidget();
}

void wxsPalette::OnUnselectWidget(wxsEvent& event)
{
    if ( event.GetWidget() == SelectedWidget )
    {
        SetInsertionTypeMask(0);
        SelectedWidget = NULL;
    }
}

void wxsPalette::OnSelectRes(wxsEvent& event)
{
    wxsResource* Res = event.GetResource();

    if ( Res )
    {
        Manager::Get()->GetMessageManager()->SetSelection(PageNum);
        Res->EditOpen();
    }

    SelectedRes = Res;

    if ( Res && Res->CanPreview() )
    {
        FindWindow(PreviewId)->Enable();
    }
    else
    {
        FindWindow(PreviewId)->Disable();
    }
}

void wxsPalette::OnUnselectRes(wxsEvent& event)
{
    if ( event.GetResource() == SelectedRes )
    {
        SelectedRes = NULL;
        FindWindow(PreviewId)->Disable();
    }
}

void wxsPalette::OnTimer(wxTimerEvent& event)
{
	wxsCoder::Get()->ProcessCodeQueue();
}

BEGIN_EVENT_TABLE(wxsPalette,wxPanel)
    EVT_RADIOBUTTON(-1,wxsPalette::OnRadio)
    EVT_BUTTON(-1,wxsPalette::OnButton)
    EVT_SELECT_RES(wxsPalette::OnSelectRes)
    EVT_UNSELECT_RES(wxsPalette::OnUnselectRes)
    EVT_SELECT_WIDGET(wxsPalette::OnSelectWidget)
    EVT_UNSELECT_WIDGET(wxsPalette::OnUnselectWidget)
    EVT_TIMER(-1,wxsPalette::OnTimer)
END_EVENT_TABLE()


syntax highlighted by Code2HTML, v. 0.9.1