struct MyFrame : wxFrame
{
    wxMenu *editmenu;
    wxString exepath;
    wxFileHistory filehistory;
    wxTextCtrl *filter, *replaces;
    wxToolBar *tb;
    int refreshhack, refreshhackinstances;
    bool tradscroll;
    BlinkTimer bt;
    wxTaskBarIcon tbi;
    wxIcon icon;
    wxNotebook *nb;

    MyFrame(const wxString &exename) : wxFrame((wxFrame *)NULL, wxID_ANY, L"Restructor", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE),
        filter(NULL), replaces(NULL), tb(NULL), refreshhack(0), refreshhackinstances(0)
    {
        sys->frame = this;

        exepath = wxFileName(exename).GetPath();

        class MyLog : public wxLog
        {
            void DoLogString(const wxChar *msg, time_t timestamp)
            {
                #ifdef WIN32
                OutputDebugString(msg);
                #else
                fputws(msg, stderr);
                #endif
            }
        };

        wxLog::SetActiveTarget(new MyLog());

        //SetBackgroundColour(*wxWHITE);

        wxInitAllImageHandlers();

        icon.LoadFile(exepath+L"/images/icon16.png", wxBITMAP_TYPE_PNG);
        SetIcon(icon);  // doesn't do anything?

        tbi.Connect(wxID_ANY, wxEVT_TASKBAR_LEFT_DCLICK, wxTaskBarIconEventHandler(MyFrame::OnTBIDBLClick), NULL, this);


        bool showtbar, showsbar;
        #ifdef __WXMAC__
        sys->cfg.Read(L"showtbar", &showtbar, false);
        #else
        sys->cfg.Read(L"showtbar", &showtbar, true);
        #endif
        sys->cfg.Read(L"showsbar", &showsbar, true);
        sys->cfg.Read(L"tradscroll", &tradscroll, false);

        filehistory.Load(sys->cfg);

        wxMenu *recentmenu = new wxMenu();
        filehistory.UseMenu(recentmenu);
        filehistory.AddFilesToMenu();

        wxMenu *filemenu = new wxMenu();
        filemenu->Append(A_NEW,          L"New\tCTRL+n"); //->SetBitmap(wxBitmap("images/nuvola/16x16/actions/filenew.png", wxBITMAP_TYPE_PNG));
        filemenu->Append(A_OPEN,         L"Open...\tCTRL+o");
        filemenu->Append(A_CLOSE,        L"Close\tCTRL+w");
        filemenu->AppendSubMenu(recentmenu, L"Recent files");
        filemenu->Append(A_SAVE,         L"Save\tCTRL+s");
        filemenu->Append(A_SAVEAS,       L"Save As...");
        filemenu->Append(A_REFACTOR,     L"Restructor\tESC");
        filemenu->Append(A_REFACTORAGGR, L"Restructor Agressively\tF4");
        filemenu->Append(A_EXIT,         L"Exit");


        wxMenuBar *menubar = new wxMenuBar();
        menubar->Append(filemenu, L"File");


        SetMenuBar(menubar);

        nb = new wxNotebook(this, wxID_ANY);
        //nb->SetPadding(wxSize(16, 2));
        //nb->SetOwnFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false));

        int resx, resy, posx, posy;
        sys->cfg.Read(L"resx", &resx, 1000);
        sys->cfg.Read(L"resy", &resy, 750);
        sys->cfg.Read(L"posx", &posx, 10);
        sys->cfg.Read(L"posy", &posy, 10);
        SetSize(resx, resy);
        SetPosition(wxPoint(posx, posy));

        bool ismax;
        sys->cfg.Read(L"maximized", &ismax, true);

        Show(TRUE);

        if(ismax) Maximize(true);   // needs to be after Show() to avoid scrollbars rendered in the wrong place?

        SetFileAssoc(exename);

        wxSafeYield();
    }

    ~MyFrame()
    {
        filehistory.Save(sys->cfg);
        if(!IsIconized())
        {
            sys->cfg.Write(L"maximized", IsMaximized());
            if(!IsMaximized())
            {
                sys->cfg.Write(L"resx", GetSize().x);
                sys->cfg.Write(L"resy", GetSize().y);
                sys->cfg.Write(L"posx", GetPosition().x);
                sys->cfg.Write(L"posy", GetPosition().y);
            }
        }
    }

    TSCanvas *NewTab(Document *doc)
    {
        TSCanvas *sw = new TSCanvas(this, nb);
        sw->doc = doc;
        doc->sw = sw;
        sw->SetScrollRate(1, 1);
        nb->InsertPage(0, sw, L"<unnamed>", true);
        sw->SetDropTarget(new DropTarget(doc->dataobjc));
        sw->SetFocus();
        return sw;
    }

    TSCanvas *GetTabByFileName(const wxString &fn)
    {
        loop(i, nb->GetPageCount())
        {
            TSCanvas *p = (TSCanvas *)nb->GetPage(i);
            if(p->doc->filename==fn) return p;
        }
        return NULL;
    }

    void OnTabChange(wxNotebookEvent &nbe)
    {
        sys->TabChange(((TSCanvas *)nb->GetPage(nbe.GetSelection()))->doc);
    }

    void AddTBIcon(wxToolBar *tb, const wxChar *name, int action, wxString file)
    {
        wxBitmap bm;
        if(bm.LoadFile(file, wxBITMAP_TYPE_PNG)) tb->AddTool(action, name, bm, bm, wxITEM_NORMAL, name);
    }

    void OnMenu(wxCommandEvent &ce)
    {
        if(filter && filter==wxWindow::FindFocus())   // FIXME: have to emulate this behavior because menu always captures these events (??)
        {
            //wxKeyEvent ke(wxEVT_CHAR);
            long from, to;
            filter->GetSelection(&from, &to);
            switch(ce.GetId())
            {
                case A_LEFT:   filter->SetInsertionPoint(from-1);   return;
                case A_RIGHT:  filter->SetInsertionPoint(to+1);     return;
                case A_DELETE: filter->Remove(from-(from==to), to); return;
            }
        }
        TSCanvas *sw = sys->GetSW();
        wxClientDC dc(sw);
        sw->DoPrepareDC(dc);
        switch(ce.GetId())
        {
            case A_ALEFT:    sw->CursorScroll(-1,  0); break;
            case A_ARIGHT:   sw->CursorScroll( 1,  0); break;
            case A_AUP:      sw->CursorScroll( 0, -1); break;
            case A_ADOWN:    sw->CursorScroll( 0,  1); break;

            case A_SHOWSBAR:   sys->cfg.Write(L"showsbar", ce.IsChecked()); sw->Status("change will take effect next run of Restructor"); break;
            case A_SHOWTBAR:   sys->cfg.Write(L"showtbar", ce.IsChecked()); sw->Status("change will take effect next run of Restructor"); break;
            case A_TRADSCROLL: sys->cfg.Write(L"tradscroll", tradscroll = ce.IsChecked()); sw->Status(tradscroll ? "Zoom now works with Alt+UP/DOWN" : "Scroll with Alt+cursor keys"); break;
            case A_MAKEBAKS:   sys->cfg.Write(L"makebaks", sys->makebaks = ce.IsChecked()); break;
            case A_TOTRAY:     sys->cfg.Write(L"totray", sys->totray = ce.IsChecked()); break;
            case A_AUTOSAVE:   sys->cfg.Write(L"autosave", sys->autosave = ce.IsChecked()); break;

            case A_SEARCHF: filter->SetFocus(); break;

            case A_EXIT: this->Close(); break;
            default:
                if(ce.GetId()>=wxID_FILE1 && ce.GetId()<=wxID_FILE9)
                {
                    wxString f(filehistory.GetHistoryFile(ce.GetId() - wxID_FILE1));
                    sw->Status(sys->Open(f));
                }
                else
                    sw->Status(sys->Action(dc, ce.GetId())); break;
        }
    }

    void OnSearch(wxCommandEvent &ce)
    {
        sys->searchstring = ce.GetString().Lower();
        sys->Refresh();
    }

    void OnCellColor(wxCommandEvent &ce) { /*sys->ColorChange(0, ce.GetInt());*/ }
    void OnTextColor(wxCommandEvent &ce) { /*sys->ColorChange(1, ce.GetInt());*/ }

    void OnSizing(wxSizeEvent  &se) {  se.Skip(); }

    void OnMaximize(wxMaximizeEvent &me) { if(sys->GetSW()) sys->GetSW()->SetFocus(); }
    void OnActivate(wxActivateEvent &ae) { if(sys->GetSW()) sys->GetSW()->SetFocus(); }

    void OnIconize(wxIconizeEvent &me)
    {
        if(me.IsIconized())
        {
            #ifdef WIN32
                if(sys->totray)
                {
                    tbi.SetIcon(icon, L"Restructor");
                    Show(false);
                }
            #endif
        }
        else
        {
            if(sys->GetSW()) sys->GetSW()->SetFocus();
        }
    }

    void OnTBIDBLClick(wxTaskBarIconEvent &e)
    {
        Show(true);
        Iconize(false);
        tbi.RemoveIcon();
    }

    void OnClosing(wxCloseEvent &ce)
    {
        if(ce.CanVeto()) while(nb->GetPageCount())
        {
            if(sys->CloseDocument())
            {
                ce.Veto();
                return;
            }
            else
            {
                nb->RemovePage(nb->GetSelection());
            }
        }

        bt.Stop();
        sys->savechecker.Stop();

        Destroy();
    }

    #ifdef WIN32
    void SetRegKey(wxChar *key, wxString val)
    {
        wxRegKey rk(key);
        rk.Create();
        rk.SetValue(L"", val);
    }
    #endif

    void SetFileAssoc(const wxString &exename)
    {
        #ifdef WIN32
            SetRegKey(L"HKEY_CLASSES_ROOT\\.rs",                              L"Restructor");
            SetRegKey(L"HKEY_CLASSES_ROOT\\Restructor",                       L"Restructor file");
            SetRegKey(L"HKEY_CLASSES_ROOT\\Restructor\\Shell\\Open\\Command", wxString(L"\"")+exename+L"\" \"%1\"");
            SetRegKey(L"HKEY_CLASSES_ROOT\\Restructor\\DefaultIcon",          wxString(L"\"")+exename+L"\",0");
        #else
            //TODO: do something similar for mac/kde/gnome?
        #endif
    }

    DECLARE_EVENT_TABLE()
};

