//cbaGUI_dialogs.cpp

#include "cbaGUI_dialogs.h"

//---------------- new beam dialog -------------------------
BEGIN_EVENT_TABLE(BeamDialog, wxDialog)
    EVT_BUTTON(ID_BT_OK, BeamDialog::OnClose)
    EVT_BUTTON(ID_BT_ESC, BeamDialog::OnClose)
    EVT_TEXT(wxID_ANY, BeamDialog::OnTcCheck)

END_EVENT_TABLE()

BeamDialog::BeamDialog(wxFrame *parent, wxWindowID id, const wxString &title)
        : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxColour(*wxWHITE));
    wxPoint pos = wxGetMousePosition();
    SetSize(pos.x, pos.y, 200, 200);

    wxBoxSizer *TcSizer = new wxBoxSizer(wxVERTICAL);

    //spin control for number of spans
    TcNum = new wxSpinCtrl(this, 1000, _T("1"), wxDefaultPosition, wxSize(180,25), wxSP_ARROW_KEYS, 1, 20, 1);
    TcSizer->Add(new wxStaticText(this, -1, _T("Number of spans:"), wxDefaultPosition, wxSize(180,20)), 0, wxTOP, 10);
    TcSizer->Add(TcNum, 0, wxEXPAND);

    //text controls
    wxArrayString labels;
    labels.Add(_T("Length of Spans:"));
    labels.Add(_T("Permanent Load:"));
    labels.Add(_T("Live Load:"));

    wxArrayString defaults;
    defaults.Add(_T("1.00"));
    defaults.Add(_T("0.00"));
    defaults.Add(_T("0.00"));

    for (int i=1001; i<=1003; i++)
    {
        TcSizer->Add(new wxStaticText(this, -1, labels[i-1001], wxDefaultPosition, wxSize(180,20)), 0, wxTOP, 10);
        TcSizer->Add(new wxTextCtrl(this, i, defaults[i-1001], wxDefaultPosition, wxSize(180,25)), 0, wxEXPAND);
    }

    //buttons
    wxBoxSizer *BtSizer = new wxBoxSizer(wxHORIZONTAL);
    BtSizer->Add(new wxButton( this, ID_BT_OK, _T("OK"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);
    BtSizer->Add(new wxButton( this, ID_BT_ESC, _T("Cancel"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);

    wxBoxSizer *Vsizer = new wxBoxSizer(wxVERTICAL);
    Vsizer->Add(TcSizer, 1, wxEXPAND | wxALIGN_LEFT | wxALL, 20);
    Vsizer->Add(BtSizer, 0, wxALIGN_CENTER | wxBOTTOM, 20);

    SetSizer(Vsizer);
    Vsizer->SetSizeHints(this);
}

void BeamDialog::OnClose(wxCommandEvent &event)
{
    text.Clear();

    int id = event.GetId();
    if (id==ID_BT_OK)
    {
        int nr = TcNum->GetValue();
        wxString nrText;
        nrText << nr;
        text.Add(nrText);

        for (int i=1001; i<=1003; i++)
        {
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(i, this);
            text.Add(ctrl->GetValue());
        }
    }

    Close(TRUE);
}


void BeamDialog::OnTcCheck(wxCommandEvent &event)
{
    //entered commas will be changed to points
    int id = event.GetId();
    if (id!=1000)   //TcNum
    {
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(id, this);
        wxString vStr=ctrl->GetValue();
        if (vStr.Find(_T(",")) > -1) vStr.Replace( _T(","),_T("."));
        ctrl->ChangeValue(vStr);
        ctrl->SetInsertionPointEnd();
    }
}


//---------------- load factor dialog -------------------------
BEGIN_EVENT_TABLE(LoadFactorDialog, wxDialog)
    EVT_BUTTON(ID_BT_OK, LoadFactorDialog::OnClose)
    EVT_BUTTON(ID_BT_ESC, LoadFactorDialog::OnClose)
    EVT_CHECKBOX(ID_CHK, LoadFactorDialog::OnChkBox)
    EVT_TEXT(wxID_ANY, LoadFactorDialog::OnTcCheck)

END_EVENT_TABLE()

LoadFactorDialog::LoadFactorDialog(wxFrame *parent, wxWindowID id, const wxString &title, wxString input)
        : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxColour(*wxWHITE));
    wxPoint pos = wxGetMousePosition();
    SetSize(pos.x, pos.y, 200, 200);

    //check box max/min
    ChkMin = new wxCheckBox(this, ID_CHK, _T("disburdening"), wxDefaultPosition, wxSize(150,25));
    ChkMin->SetValue(true);

    //text controls
    wxArrayString labels;
    labels.Add(_T("permanent loads:"));
    labels.Add(_T("live loads:"));
    labels.Add(_T("permanent loads (min):"));
    labels.Add(_T("live loads (min):"));

    wxBoxSizer *TcMaxSizer = new wxBoxSizer(wxVERTICAL);
    for (int i=0; i<2; i++)
    {
        TcMaxSizer->Add(new wxStaticText(this, -1, labels[i], wxDefaultPosition, wxSize(150,20)), 0, wxTOP, 10);
        TcMaxSizer->Add(new wxTextCtrl(this, 1000+i, _T(""), wxDefaultPosition, wxSize(150,25)), 0, wxEXPAND);
    }

    //minimum load factors
    wxBoxSizer *TcMinSizer = new wxBoxSizer(wxVERTICAL);
    for (int i=2; i<4; i++)
    {
        wxTextCtrl *min = new wxTextCtrl(this, 1000+i, _T(""), wxDefaultPosition, wxSize(150,25), wxTE_RICH);
        min->SetDefaultStyle(wxTextAttr(*wxRED));
        TcMinSizer->Add(new wxStaticText(this, -1, labels[i], wxDefaultPosition, wxSize(150,20)), 0, wxTOP, 10);
        TcMinSizer->Add(min, 0, wxEXPAND);
    }

    //buttons
    wxBoxSizer *BtSizer = new wxBoxSizer(wxHORIZONTAL);
    BtSizer->Add(new wxButton( this, ID_BT_OK, _T("OK"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);
    BtSizer->Add(new wxButton( this, ID_BT_ESC, _T("Cancel"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);

    Vsizer = new wxBoxSizer(wxVERTICAL);
    Vsizer->Add(ChkMin, 0,  wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(TcMaxSizer, 1, wxEXPAND | wxALIGN_LEFT | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(TcMinSizer, 1,  wxEXPAND | wxALIGN_LEFT | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(BtSizer, 0, wxALIGN_CENTER | wxALL, 20);

    SetSizer(Vsizer);
    Vsizer->SetSizeHints(this);

    //set defaults
    text=input;
    bool disb(false);
    for (int i=0; i<4; i++)
    {
        wxTextCtrl *text = (wxTextCtrl*) FindWindowById(1000+i, this);
        text->ChangeValue(_T("1.00"));
        if (i==3) text->ChangeValue(_T("0.00"));

        wxString value = input.BeforeFirst(_T(' '));
        if (!value.IsEmpty())
        {
            text->ChangeValue(value);
            if (i>1) disb=true;
        }
        input = input.AfterFirst(_T(' '));
    }

    //set checkbox if disburdening factors are given
    if (disb) ChkMin->SetValue(true);
    else
    {
        ChkMin->SetValue(false);
        Vsizer->Hide(2);
        Vsizer->SetSizeHints(this);
        Vsizer->Fit(this);
    }
}


void LoadFactorDialog::OnClose(wxCommandEvent &event)
{
    if (event.GetId()==ID_BT_OK)
    {
        text.Empty();
        wxChar spc(_T(' '));
        wxString valMax, valMin;

        for (int i=0; i<4; i++)
        {
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1000+i, this);
            wxString vStr = ctrl->GetValue();
            double d; vStr.ToDouble(&d); vStr.Printf(_T("%4.2f"),d);
            if (i<2) valMax+= vStr+spc; else valMin+= vStr+spc;
        }
        valMax=valMax.BeforeLast(spc);
        valMin=valMin.BeforeLast(spc);

        //check if factors are default
        if (valMax!=_T("1.00 1.00")) text+=valMax;
        if (ChkMin->IsChecked())
        {
            if (valMin!=_T("1.00 0.00")) text+=spc+valMin;
            if (valMax==_T("1.00 1.00") && valMin!=_T("1.00 0.00")) text=valMax+spc+valMin;
        }
    }

    Close(TRUE);
}



void LoadFactorDialog::OnChkBox(wxCommandEvent &event)
{
    if (event.IsChecked())
    {
        Vsizer->Show(2, true);
        Vsizer->SetSizeHints(this);
        Vsizer->Fit(this);
    }
    else
    {
        Vsizer->Hide(2);
        Vsizer->SetSizeHints(this);
        Vsizer->Fit(this);
    }
}


void LoadFactorDialog::OnTcCheck(wxCommandEvent &event)
{
    //entered commas will be changed to points
    wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(event.GetId(), this);
    wxString vStr=ctrl->GetValue();
    if (vStr.Find(_T(",")) > -1) vStr.Replace( _T(","),_T("."));
    ctrl->ChangeValue(vStr);
    ctrl->SetInsertionPointEnd();
}


//---------------- constraints dialog -------------------------
BEGIN_EVENT_TABLE(ConstraintsDialog, wxDialog)
    EVT_BUTTON(ID_BT_OK, ConstraintsDialog::OnClose)
    EVT_BUTTON(ID_BT_ESC, ConstraintsDialog::OnClose)

END_EVENT_TABLE()

ConstraintsDialog::ConstraintsDialog(wxFrame *parent, wxWindowID id, const wxString &title, wxArrayString values)
        : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxColour(*wxWHITE));
    wxPoint pos = wxGetMousePosition();
    SetSize(pos.x, pos.y, 200, 200);

    //grid
    grid = new wxGrid(this, -1, wxPoint(0,0), wxSize(200,120));
    grid->CreateGrid(0,0,wxGrid::wxGridSelectCells);
    grid->SetLabelBackgroundColour(*wxWHITE);
    grid->SetColLabelSize(20);
    grid->SetRowLabelSize(40);
    grid->SetDefaultColSize(75);
	grid->SetDefaultRowSize(20);
	grid->SetDefaultCellAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE );

 	grid->AppendCols(2);
	grid->SetColLabelValue(0, _T("def"));
	grid->SetColLabelValue(1, _T("rot"));

	//expl
    wxStaticText *expl = new wxStaticText(this, -1, _T(""), wxDefaultPosition, wxSize(150,60));
    expl->SetLabel(_T("-1 ... supported\n 0 ... not supported\n>0 ... spring\n"));

    //buttons
    wxBoxSizer *BtSizer = new wxBoxSizer(wxHORIZONTAL);
    BtSizer->Add(new wxButton(this, ID_BT_OK, _T("OK"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);
    BtSizer->Add(new wxButton(this, ID_BT_ESC, _T("Cancel"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);

    wxBoxSizer *Vsizer = new wxBoxSizer(wxVERTICAL);
    Vsizer->Add(grid, 1, wxEXPAND | wxGROW | wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(expl, 0, wxALIGN_CENTER | wxTOP, 10);
    Vsizer->Add(BtSizer, 0, wxALIGN_CENTER | wxBOTTOM, 20);

    SetSizer(Vsizer );
    Vsizer->SetSizeHints(this);

    //set values
    int rows=int(values.GetCount()/2);
    for (int i=0; i<rows; i++)
    {
        grid->AppendRows(1);
        grid->SetCellValue(i, 0, values[i*2]);
        grid->SetCellValue(i, 1, values[i*2+1]);
    }
}

void ConstraintsDialog::OnClose(wxCommandEvent &event)
{
    values.Clear();

    int id = event.GetId();
    if (id==ID_BT_OK)
    {
        int cols=grid->GetNumberCols();
        int rows=grid->GetNumberRows();
        for (int i=0; i<rows; i++)
            for (int j=0; j<cols; j++)
                values.Add(grid->GetCellValue(i, j));
    }

    Close(TRUE);
}


//---------------- materials/sections dialog -------------------------
BEGIN_EVENT_TABLE(MatSecDialog, wxDialog)
    EVT_BUTTON(ID_BT_OK, MatSecDialog::OnClose)
    EVT_BUTTON(ID_BT_ESC, MatSecDialog::OnClose)
    EVT_TREE_SEL_CHANGED(ID_MAT_TREE, MatSecDialog::OnMatChanged)
    EVT_TREE_SEL_CHANGED(ID_SEC_TREE, MatSecDialog::OnSecChanged)
    EVT_LIST_ITEM_SELECTED(ID_MAT_LIST, MatSecDialog::OnMatTable)
    EVT_LIST_ITEM_SELECTED(ID_SEC_LIST, MatSecDialog::OnSecTable)
    EVT_CHECKBOX(ID_CHK_ROT, MatSecDialog::OnChkRot)
    EVT_CHECKBOX(ID_CHK_HOL, MatSecDialog::OnChkHol)
    EVT_BUTTON(ID_BT_SET, MatSecDialog::OnSetRes)
    EVT_TEXT(wxID_ANY, MatSecDialog::OnTcCheck)


END_EVENT_TABLE()

MatSecDialog::MatSecDialog(wxFrame *parent, wxWindowID id, const wxString &title)
        : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxColour(*wxWHITE));
    wxPoint pos = wxGetMousePosition();
    SetSize(pos.x, pos.y, 300, 300);

	//material database
    MatTree = new wxTreeCtrl(this, ID_MAT_TREE, wxDefaultPosition, wxSize(120,180));
    MatTree->AddRoot(_T("materials"));
	MatList = new wxListCtrl(this, ID_MAT_LIST, wxDefaultPosition, wxSize(300,180), wxLC_REPORT);

	wxBoxSizer *MatSizer = new wxBoxSizer(wxHORIZONTAL);
    MatSizer->Add(MatTree, 0, wxEXPAND | wxLEFT, 10);
    MatSizer->Add(MatList, 1, wxEXPAND | wxLEFT, 10);

    //section database
    SecTree = new wxTreeCtrl(this, ID_SEC_TREE, wxDefaultPosition, wxSize(120,180));
	wxTreeItemId rootId = SecTree->AddRoot(_T("sections"));
    defId = SecTree->AppendItem(rootId, _T("def"));
    dbId = SecTree->AppendItem(rootId, _T("db"));
    SecTree->Expand(SecTree->GetRootItem());
    SecList = new wxListCtrl(this, ID_SEC_LIST, wxDefaultPosition, wxSize(300,180), wxLC_REPORT);

    //defined sections
    SecTree->AppendItem(defId, _T("Rect"));
    SecTree->AppendItem(defId, _T("Isec"));
    SecTree->AppendItem(defId, _T("Tube"));
    SecTree->Expand(defId);

    wxPanel *PanelSec = new wxPanel(this, -1, wxDefaultPosition, wxSize(100,100));
    wxArrayString dim;
    dim.Add(_T("h"));
    dim.Add(_T("b"));
    dim.Add(_T("t"));
    dim.Add(_T("s"));

    for (int i=0; i<4; i++)
    {
        new wxStaticText(PanelSec, 800+i, dim[i], wxPoint(0,5+i*30), wxSize(45,25));
        new wxTextCtrl(PanelSec, 900+i, _T(""), wxPoint(50,i*30), wxSize(50,25));
    }

    wxBoxSizer *V2sizer = new wxBoxSizer(wxVERTICAL);
    V2sizer->Add(PanelSec, 1, wxLEFT, 10);
    V2sizer->Add(new wxButton( this, ID_BT_SET, _T("Set >>"), wxDefaultPosition, wxSize(60,25)), 0, wxALIGN_RIGHT);

    //drawing window
    secgraph = new SecGraph;
	secgraph->Create(this, -1, wxDefaultPosition, wxSize(100,100), wxVSCROLL);

    DefSec = new wxBoxSizer(wxHORIZONTAL);
    DefSec->Add(secgraph, 1, wxEXPAND);
    DefSec->Add(V2sizer, 0, wxEXPAND | wxALL, 10);

    SecSizer = new wxBoxSizer(wxHORIZONTAL);
    SecSizer->Add(SecTree, 0, wxEXPAND | wxLEFT, 10);
    SecSizer->Add(SecList, 1, wxEXPAND | wxLEFT, 10);
    SecSizer->Add(DefSec, 1, wxEXPAND | wxLEFT, 10);

    //checkbox for 90° rotation
    ChkRot = new wxCheckBox(this, ID_CHK_ROT, _T("90°"), wxDefaultPosition, wxSize(120,30));
    ChkRot->SetValue(false);

    //check box solid/hollow
    ChkHol = new wxCheckBox(this, ID_CHK_HOL, _T("hollow"), wxDefaultPosition, wxSize(120,30));
    ChkHol->SetValue(false);

    wxBoxSizer *ChkSizer = new wxBoxSizer(wxHORIZONTAL);
    ChkSizer->Add(ChkRot, 0, wxLEFT, 10);
    ChkSizer->Add(ChkHol, 1, wxLEFT, 10);

    //text controls for results
    wxGridSizer *ResSizer = new wxGridSizer(3);
    for (int i=0; i<6; i++)
    {
        int tc(1000);
        wxString label;
        switch (i)
        {
            case 0 : tc= 1000; label=_T("Elasticity"); break;
            case 1 : tc= 1001; label=_T("Density"); break;
            case 2 : tc= 1004; label=_T("Section Modulus"); break;
            case 3 : tc= 1003; label=_T("Inertia"); break;
            case 4 : tc= 1002; label=_T("Section Area"); break;
            case 5 : tc= 1005; label=_T("Shear Area"); break;
        }

        wxPanel *panel = new wxPanel(this, -1, wxDefaultPosition, wxSize(150,45));
        new wxStaticText(panel, tc+100, label, wxPoint(0,0), wxSize(150,20));
        new wxTextCtrl(panel, tc, _T(""), wxPoint(0,20), wxSize(150,25));
        ResSizer->Add(panel, 0, wxEXPAND | wxALL, 5);
    }

    //buttons
    wxBoxSizer *BtSizer = new wxBoxSizer(wxHORIZONTAL);
    BtSizer->Add(new wxButton( this, ID_BT_OK, _T("OK"), wxDefaultPosition, wxSize(80,25)), 0, wxALL, 10);
    BtSizer->Add(new wxButton( this, ID_BT_ESC, _T("Cancel"), wxDefaultPosition, wxSize(80,25)), 0, wxALL, 10);

    Vsizer = new wxBoxSizer(wxVERTICAL);
    Vsizer->Add(MatSizer, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(SecSizer, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(ChkSizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 20);
    Vsizer->Add(ResSizer, 0, wxEXPAND | wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 25);
    Vsizer->Add(BtSizer, 0, wxALIGN_CENTER | wxALL, 20);

    SetSizer(Vsizer);
    Vsizer->SetSizeHints(this);


}

void MatSecDialog::OnClose(wxCommandEvent &event)
{
    int id = event.GetId();
    if (id!=ID_BT_OK)
    {
        for (int i=0; i<6; i++)
        {
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1000+i, this);
            ctrl->Clear();
        }
    }
    Close(TRUE);
}


void MatSecDialog::OnMatChanged(wxTreeEvent& event)
{
    wxTreeItemId itemId = event.GetItem();
    if (itemId!=MatTree->GetRootItem())
    {
        wxString table = MatTree->GetItemText(itemId);
        SetMatList(table);
    }
    else
    {
        if (MatTree->ItemHasChildren(itemId)) MatList->ClearAll();
    }

    //clear textcontrols
    for (int i=0; i<2;  i++)
    {
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1000+i, this);
        ctrl->Clear();
    }
}


void MatSecDialog::OnSecChanged(wxTreeEvent& event)
{
    wxTreeItemId item = event.GetItem();
    if (item!=SecTree->GetRootItem())
    {
        if (SecTree->GetItemParent(item)!=SecTree->GetRootItem())
        {
            wxString table = SecTree->GetItemText(item);

            //defined section
            if (SecTree->GetItemParent(item)==defId)
            {
                //copy table values coming from database
                wxTreeItemId fromId = event.GetOldItem();
                if (SecTree->GetItemParent(fromId)==dbId) CopyTableToTc(SecTree->GetItemText(fromId));

                ShowDefSec(true);
                secgraph->SetType(table, ChkHol->GetValue(), ChkRot->GetValue());
                CalcSec();
                UpdateSecTc();
            }

            //section from database
            if (SecTree->GetItemParent(item)==dbId)
            {
                ShowDefSec(false);
                SetSecList(table);
            }
        }
        else
        {
            ShowDefSec(false);
            SecList->ClearAll();
        }
    }
    else
    {
        ShowDefSec(false);
        SecList->ClearAll();
    }

     //clear textcontrols
    if (SecTree->GetItemParent(item)!=defId)
    {
        for (int i=2; i<6;  i++)
        {
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1000+i, this);
            ctrl->Clear();
        }
    }
}

void MatSecDialog::OnMatTable(wxListEvent& event)
{
    wxListItem item;
    item.m_itemId = event.m_itemIndex;

    //set elasticity & density
    item.m_col = 1; item.m_mask = wxLIST_MASK_TEXT;
    MatList->GetItem(item); wxString E = item.m_text;

    item.m_col = 2; item.m_mask = wxLIST_MASK_TEXT;
    MatList->GetItem(item); wxString rho = item.m_text;

    //convert unit
    wxChar cs(_T(','));
    double f = ConvUnit(dbMatUnit.BeforeFirst(cs), fcUnit, _T("1"));
    double l2 = ConvUnit(dbMatUnit.AfterFirst(cs), lnUnit, _T("2"));
    double l3 = ConvUnit(dbMatUnit.AfterFirst(cs), lnUnit, _T("3"));
    if (l2>0) E = sMult(E, f/l2);
    if (l3>0) rho = sMult(rho, f/l3);

    wxTextCtrl *ctrl;
    ctrl = (wxTextCtrl*) FindWindowById(1000, this); ctrl->ChangeValue(E);
    ctrl = (wxTextCtrl*) FindWindowById(1001, this); ctrl->ChangeValue(rho);
}


void MatSecDialog::OnSecTable(wxListEvent& event)
{
    wxListItem item;
    item.m_itemId = event.m_itemIndex;

    wxString u_exp(_T("2432"));

    for (int i=0; i<4;  i++)
    {
        item.m_col = i+1;
        item.m_mask = wxLIST_MASK_TEXT;
        SecList->GetItem(item);
        wxString val = item.m_text;
        val = sMult(val, ConvUnit(dbSecUnit, lnUnit, u_exp.Mid(i,1)));
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1002+i, this);
        ctrl->ChangeValue(val);
    }
}


void MatSecDialog::OnChkRot(wxCommandEvent &event)
{
    //rotate defined section
    for (int i=0; i<4; i+=2)
    {
        wxTextCtrl *ctrl1 = (wxTextCtrl*) FindWindowById(900+i, this);
        wxTextCtrl *ctrl2 = (wxTextCtrl*) FindWindowById(900+i+1, this);
        wxString swap = ctrl1->GetValue();
        ctrl1->ChangeValue(ctrl2->GetValue());
        ctrl2->ChangeValue(swap);
    }

    //remember selection
    wxTreeItemId t_item = SecTree->GetSelection();
    long l_item = -1;
    l_item = SecList->GetNextItem(l_item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);

    //trigger event to refresh
    SecTree->SelectItem(SecTree->GetItemParent(t_item));
    SecTree->SelectItem(t_item);
    if (l_item!=-1) SecList->SetItemState(l_item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
}


void MatSecDialog::OnChkHol(wxCommandEvent &event)
{
    //trigger event to refresh
    wxTreeItemId t_item = SecTree->GetSelection();
    SecTree->SelectItem(SecTree->GetItemParent(t_item));
    SecTree->SelectItem(t_item);
}


void MatSecDialog::OnSetRes(wxCommandEvent &event)
{
    CalcSec();
}


void MatSecDialog::OnTcCheck(wxCommandEvent &event)
{
    //entered commas will be changed to points
    wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(event.GetId(), this);
    wxString vStr=ctrl->GetValue();
    if (vStr.Find(_T(",")) > -1) vStr.Replace( _T(","),_T(".") );
    ctrl->ChangeValue(vStr);
    ctrl->SetInsertionPointEnd();
}


void MatSecDialog::SetDbLoc(wxString mat, wxString sec)
{
    //material database
    if (wxFile::Exists(mat))
    {
        dbMat=mat;
        wxChar cs(_T(','));
        wxString tables = QueryDB(dbMat);
        dbMatUnit = tables.BeforeFirst(cs); tables=tables.AfterFirst(cs);
        dbMatUnit+= cs+tables.BeforeFirst(cs); tables=tables.AfterFirst(cs);
        while (!tables.IsEmpty())
        {
            MatTree->AppendItem(MatTree->GetRootItem(), tables.BeforeFirst(cs));
            tables=tables.AfterFirst(cs);
        }
        MatTree->Expand(MatTree->GetRootItem());
        MatTree->ScrollTo(MatTree->GetRootItem());
    }
    else
    {
        MatList->InsertColumn(0, _T(""));
        MatList->InsertItem(0, _T("Material database not found, choose in settings!"));
        MatList->SetColumnWidth(0, wxLIST_AUTOSIZE );
    }

    //section database
    if (wxFile::Exists(sec))
    {
        dbSec=sec;
        wxChar cs(_T(','));
        wxString tables = QueryDB(dbSec);
        dbSecUnit = tables.BeforeFirst(cs); tables=tables.AfterFirst(cs);
        while (!tables.IsEmpty())
        {
            SecTree->AppendItem(dbId, tables.BeforeFirst(cs));
            tables=tables.AfterFirst(cs);
        }
        SecTree->Expand(dbId);
        SecTree->ScrollTo(SecTree->GetRootItem());

        //dbUnit = defSecUnit
        for (int i=0; i<4; i++)
        {
            wxStaticText *txt = (wxStaticText*) FindWindowById(800+i, this);
            wxString label=txt->GetLabel();
            label+=_T(" [")+dbSecUnit+_T("]");
            txt->SetLabel(label);
        }
    }

    else
    {
        SecList->InsertColumn(0, _T(""));
        SecList->InsertItem(0, _T("Section database not found, choose in settings!"));
        SecList->SetColumnWidth(0, wxLIST_AUTOSIZE );
    }
}


void MatSecDialog::SetUnits(wxString fc, wxString ln)
{
    fcUnit=fc;
    lnUnit=ln;

    //set label units
    for (int i=0; i<6; i++)
    {
        wxStaticText *txt = (wxStaticText*) FindWindowById(1100+i, this);
        wxString label = txt->GetLabel();
        switch (i)
        {
            case 0 : label+=_T(" [")+fcUnit+_T("/")+lnUnit+_T("2]"); break;
            case 1 : label+=_T(" [")+fcUnit+_T("/")+lnUnit+_T("3]"); break;
            case 2 : label+=_T(" [")+lnUnit+_T("2]"); break;
            case 3 : label+=_T(" [")+lnUnit+_T("4]"); break;
            case 4 : label+=_T(" [")+lnUnit+_T("3]"); break;
            case 5 : label+=_T(" [")+lnUnit+_T("2]"); break;
        }
        txt->SetLabel(label);
    }

    //set default len unit if section database is not fount
    if (dbSecUnit.IsEmpty())
    {
        dbSecUnit=lnUnit;
        for (int i=0; i<4; i++)
        {
            wxStaticText *txt = (wxStaticText*) FindWindowById(800+i, this);
            wxString label=txt->GetLabel();
            label+=_T(" [")+dbSecUnit+_T("]");
            txt->SetLabel(label);
        }
    }
}


void MatSecDialog::SetMat(wxString input)
{
    if (!dbMat.IsEmpty())
    {
        wxString mat=input.BeforeFirst(_T(' '));
        wxString table=input.AfterFirst(_T(' '));

        //try choosing table in tree
        bool found(false);
        wxTreeItemIdValue cookie;
        wxTreeItemId t_item = MatTree->GetFirstChild(MatTree->GetRootItem(), cookie);
        while(t_item.IsOk())
        {
            if (MatTree->GetItemText(t_item).MakeUpper()==mat.MakeUpper())
            {
                MatTree->SelectItem(t_item);
                found=true;
                break;
            }
            t_item = MatTree->GetNextChild(MatTree->GetRootItem(), cookie);
        }

        //set table to list if material is found
        if (found)
        {
            long l_item = MatList->FindItem(-1, table);
            if (l_item!=-1)
            {
                MatList->SetItemState(l_item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
                MatList->EnsureVisible(l_item);
            }
        }

        //set default if not
        if (input.IsEmpty())
        {
            wxTreeItemIdValue cookie;
            MatTree->SelectItem(MatTree->GetFirstChild(MatTree->GetRootItem(), cookie));
        }
    }
}


void MatSecDialog::SetSec(wxString input)
{
    //set default if no section is given
    if (input.IsEmpty())
    {
        wxTreeItemIdValue cookie;
        SecTree->SelectItem(SecTree->GetFirstChild(dbId, cookie));
    }

    //check rotation (last value)
    wxChar spc(_T(' '));
    wxString rot = input.AfterLast(spc).MakeUpper();
    if (rot==_T("ROT"))
    {
        ChkRot->SetValue(true);
        input=input.BeforeLast(spc);
    }
    else ChkRot->SetValue(false);

    //get section type
    wxString type = input.BeforeFirst(spc).MakeUpper();
    input=input.AfterFirst(spc);

    //try choosing table in tree
    bool found(false);
    wxTreeItemIdValue cookie;
    wxTreeItemId t_item = SecTree->GetFirstChild(dbId, cookie);
    while(t_item.IsOk())
    {
        if (SecTree->GetItemText(t_item).MakeUpper()==type)
        {
            SecTree->SelectItem(t_item);
            found=true;
            break;
        }
        t_item = SecTree->GetNextChild(dbId, cookie);
    }

    //set table to list if section is found
    if (found)
    {
        long l_item = SecList->FindItem(-1, input);
        if (l_item!=-1)
        {
            SecList->SetItemState(l_item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
            SecList->EnsureVisible(l_item);
        }
    }

    //try defined sections
    if (type==_T("RECT"))
    {
        int row(0);
        while (!input.IsEmpty())
        {
            wxString val=input.BeforeFirst(spc); input=input.AfterFirst(spc);
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(900+row, this);
            ctrl->ChangeValue(val);
            row++;
            if (row==4) break;
        }
        if (row>2) ChkHol->SetValue(true); else ChkHol->SetValue(false);
        wxTreeItemIdValue cookie;
        SecTree->SelectItem(SecTree->GetFirstChild(defId, cookie));
    }

    if (type==_T("ISEC"))
    {
        int row(0);
        while (!input.IsEmpty())
        {
            wxString val=input.BeforeFirst(spc); input=input.AfterFirst(spc);
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(900+row, this);
            ctrl->ChangeValue(val);
            row++;
            if (row==4) break;
        }
        ChkHol->SetValue(false);
        wxTreeItemIdValue cookie;
        SecTree->GetFirstChild(defId, cookie);
        SecTree->SelectItem(SecTree->GetNextChild(defId, cookie));
    }

    if (type==_T("TUBE"))
    {
        wxString val=input.BeforeFirst(spc); input=input.AfterFirst(spc);
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(901, this);
        ctrl->ChangeValue(val);
        val=input.BeforeFirst(spc);
        if (!val.IsEmpty())
        {
            ctrl = (wxTextCtrl*) FindWindowById(903, this);
            ctrl->ChangeValue(val);
            ChkHol->SetValue(true);
        }
        else ChkHol->SetValue(false);
        ChkRot->SetValue(false);
        wxTreeItemIdValue cookie;
        SecTree->GetFirstChild(defId, cookie);
        SecTree->GetNextChild(defId, cookie);
        SecTree->SelectItem(SecTree->GetNextChild(defId, cookie));
    }

}


void MatSecDialog::SetEI(wxString E, wxString I)
{
    //if there´s no section nor material
    wxTextCtrl *ctrl;
    ctrl = (wxTextCtrl*) FindWindowById(1000, this); ctrl->ChangeValue(E);
    ctrl = (wxTextCtrl*) FindWindowById(1003, this); ctrl->ChangeValue(I);
}


wxArrayString MatSecDialog::GetItems()
{
    text.Clear();
    for (int i=0; i<6; i++)
    {
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1000+i, this);
        text.Add(ctrl->GetValue());
    }

    //append material
    wxString mat;
    bool sel(false);
    wxTreeItemId item_m = MatTree->GetSelection();
    if (item_m!=MatTree->GetRootItem())
    {
        mat = MatTree->GetItemText(item_m);
        long item = -1;
        for ( ;; )
        {
            item = MatList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
            if (item==-1) break;
            mat+=_T(" ")+MatList->GetItemText(item);
            sel=true;

       }
    }
    if (!sel) mat.Empty();  //only chosen material
    text.Add(mat);

    //append section
    wxString sec;
    sel=false;
    wxTreeItemId item_s = SecTree->GetSelection();
    if (item_s!=SecTree->GetRootItem())
    {
        if (SecTree->GetItemParent(item_s)==defId)
        {
            sec=SecTree->GetItemText(item_s);
            for (int i=0; i<4; i++)
            {
                wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(900+i, this);
                if (ctrl->IsShown()) sec+=_T(" ")+ctrl->GetValue();
            }
            if (ChkRot->GetValue()) sec+=_T(" rot");
            sel=true;
        }

        if (SecTree->GetItemParent(item_s)==dbId)
        {
            sec=SecTree->GetItemText(item_s);
            long item = -1;
            for ( ;; )
            {
                item = SecList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                if (item==-1) break;
                sec+=_T(" ")+SecList->GetItemText(item);
                sel=true;
            }
            if (ChkRot->GetValue()) sec+=_T(" rot");
         }
    }
    if (!sel) sec.Empty();
    text.Add(sec);

    return text;
}


void MatSecDialog::SetMatList(wxString table)
{
    //set cols and labels
    MatList->ClearAll();
    MatList->InsertColumn(0, table);

    //set tables
    wxArrayString values = QueryTable(dbMat, table, _T("E,rho"));
    wxChar cs(_T(','));

    MatList->InsertColumn(1, (_T("E [")+dbMatUnit.BeforeFirst(cs)+_T("/")+dbMatUnit.AfterLast(cs)+_T("2]")));
    MatList->InsertColumn(2, (_T("rho [")+dbMatUnit.BeforeFirst(cs)+_T("/")+dbMatUnit.AfterLast(cs)+_T("3]")));

    //attach values to list
    for (size_t row=0; row<values.GetCount(); row++)
    {
        wxString line = values[row];
        MatList->InsertItem(row, line.BeforeFirst(cs)); line=line.AfterFirst(cs);
        MatList->SetItem(row, 1, line.BeforeFirst(cs)); line=line.AfterFirst(cs);
        MatList->SetItem(row, 2, line.BeforeFirst(cs)); line=line.AfterFirst(cs);
    }
}


void MatSecDialog::SetSecList(wxString table)
{
    wxString select = _T("A,Iy,Wy,Az");
    if (ChkRot->GetValue()) select = _T("A,Iz,Wz,Ay");
    wxArrayString values = QueryTable(dbSec, table, select);
    wxString u_exp(_T("2432"));
    wxChar cs(_T(','));

    //set cols and labels
    SecList->ClearAll();
    SecList->InsertColumn(0, table);

    int col(1);
    while (!select.IsEmpty())
    {
        wxString label = (select.BeforeFirst(cs)+_T(" [")+dbSecUnit+u_exp.Mid(col-1,1)+_T("]"));
        SecList->InsertColumn(col, label);
        select=select.AfterFirst(cs);
        col++;
    }

    //attach values to list
    for (size_t row=0; row<values.GetCount(); row++)
    {
        wxString line = values[row];
        wxString name = line.BeforeFirst(cs); line=line.AfterFirst(cs);
        SecList->InsertItem(row, name);
        col=1;
        while (!line.IsEmpty())
        {
            SecList->SetItem(row, col, line.BeforeFirst(cs));
            line=line.AfterFirst(cs);
            col++;
        }
    }
}


void MatSecDialog:: CopyTableToTc(wxString table)
{
    //set defined section from selected db
    wxString sel;
    long item = -1;
    for ( ;; )
    {
        item = SecList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
        if (item==-1) break;
        sel = SecList->GetItemText(item);
    }

    if (!sel.IsEmpty())
    {
        wxString h, t, b, s;
        wxChar cs(_T(','));

        //query table twice because it searches recursively
        wxArrayString tbls = QueryTable(dbSec, table, _T("h,t"));
        for (size_t row=0; row<tbls.GetCount(); row++)
        {
            wxString name = tbls[row].BeforeFirst(cs);
            if (name==sel)
            {
                h = tbls[row].AfterFirst(cs);
                t = h.AfterFirst(cs).BeforeLast(cs); h = h.BeforeFirst(cs);
                break;
            }
        }

        tbls = QueryTable(dbSec, table, _T("b,s"));
        for (size_t row=0; row<tbls.GetCount(); row++)
        {
            wxString name = tbls[row].BeforeFirst(cs);
            if (name==sel)
            {
                b = tbls[row].AfterFirst(cs);
                s = b.AfterFirst(cs).BeforeLast(cs); b = b.BeforeFirst(cs);
                break;
            }
        }
        if (b.IsEmpty()) b=h;
        if (s.IsEmpty()) s=t;

        //check rotation
        if (ChkRot->GetValue())
        {
            wxString swap;
            swap=h; h=b; b=swap;
            swap=t; t=s; s=t;
        }

        //fill into tc
        for (int i=0; i<4; i++)
        {
            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(900+i, this);

            switch (i)
            {
                case 0: ctrl->ChangeValue(h); break;
                case 1: ctrl->ChangeValue(b); break;
                case 2: ctrl->ChangeValue(t); break;
                case 3: ctrl->ChangeValue(s); break;
            }
        }

        //set section to hollow
        if (SecTree->GetItemText(SecTree->GetSelection()).MakeUpper()!=_T("ISEC"))
            ChkHol->SetValue(true);
        else ChkHol->SetValue(false);
    }
}


wxString MatSecDialog::QueryDB(wxString dbLoc)
{
    //query database to get tables
    wxString tables;

    //check file beforehand otherwise wxwidgets will throw an exception
    wxString head;
    if (wxFile::Exists(dbLoc))
    {
        wxTextFile *xmlFile = new wxTextFile;
        xmlFile->Open(dbLoc);
        head = xmlFile->GetFirstLine();
        xmlFile->Close();
    }

    if (head.Left(5)==_T("<?xml"))
    {
        wxXmlDocument doc;
        if (doc.Load(dbLoc))
        {
            wxChar cs(_T(','));
            wxString tbl;
            wxXmlNode *child = doc.GetRoot()->GetChildren();
            while (child)
            {
                wxString nStr=child->GetName();
                if (nStr==_T("units"))  //get units
                {
                    wxXmlNode *subchild = child->GetChildren();
                    while (subchild)
                    {
                        tables+=subchild->GetNodeContent()+cs;
                        subchild = subchild->GetNext();
                    }
                }
                else if (nStr!=tbl)          //get table names
                {
                    if (child->GetType()==1)
                    {
                        tables+=nStr+cs;
                        tbl=nStr;
                    }
                }
                child = child->GetNext();
            }
        }
    }
    return tables;
}


wxArrayString MatSecDialog::QueryTable(wxString dbLoc, wxString table, wxString select)
{
     //query database to get values for a certain table
    wxArrayString values;
    wxXmlDocument doc;
    if (doc.Load(dbLoc))
    {
        wxXmlNode *child = doc.GetRoot()->GetChildren();
        while (child)
        {
            if (child->GetName()==table)
            {
                wxXmlNode *subchild = child->GetChildren();
                wxChar cs(_T(','));
                wxString val(subchild->GetNodeContent()+cs);   //get the name

                wxString sel(select);
                while (subchild)
                {
                    wxString label=sel.BeforeFirst(cs);
                    if (subchild->GetName()==label)
                    {
                        val+=subchild->GetNodeContent()+cs;
                        sel=sel.AfterFirst(cs);
                    }
                    subchild = subchild->GetNext();
                }
                values.Add (val);
            }
            child = child->GetNext();
        }
    }
    return values;
}



double MatSecDialog::ConvUnit(wxString from, wxString to, wxString u_exp)
{
    double f(1);
    //units are related to kN, m
    wxArrayString units;
    units.Add(_T("kN, 1"));
    units.Add(_T("N, 1000"));
    units.Add(_T("kip, 0.22480894"));
    units.Add(_T("m, 1"));
    units.Add(_T("cm, 100"));
    units.Add(_T("mm, 1000"));
    units.Add(_T("ft, 3.28084"));
    units.Add(_T("in, 39.37008"));

    for (size_t i=0; i<units.GetCount(); i++)
    {
        if (units[i].BeforeFirst(_T(','))==from)
        {
            units[i].AfterFirst(_T(',')).ToDouble(&f);
            for (size_t j=0; j<units.GetCount(); j++)
            {
                if (units[j].BeforeFirst(_T(','))==to)
                {
                    double t;
                    units[j].AfterFirst(_T(',')).ToDouble(&t);
                    f=t/f;
                }
            }
        }
    }

    long e;
    u_exp.ToLong(&e);
    return pow(f,e);
}


wxString MatSecDialog::sMult(wxString str, double f)
{
    double val;
    str.ToDouble(&val);
    val*=f;
    wxString rStr;
    rStr.Printf(_T("%1.2e"), val);
    return rStr;
}


void MatSecDialog::ShowDefSec(bool set)
{
    int hd(1), sh(2);
    if (!set) { hd=2; sh=1; }

    ChkHol->Show(set);
    SecSizer->Hide(hd);
    SecSizer->Show(sh, true);
    Vsizer->SetSizeHints(this);
    Vsizer->Fit(this);

    //resize the dialog to fit all in
    wxSize sz = this->GetClientSize();
    sz.SetHeight(sz.GetHeight()+1);
    this->SetClientSize(sz);
}


void MatSecDialog::UpdateSecTc()
{
    wxString table = SecTree->GetItemText(SecTree->GetSelection());

    for (int i=0; i<4; i++)
    {
        wxStaticText *txt = (wxStaticText*) FindWindowById(800+i, this);
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(900+i, this);

        bool set;
        if (i==1)   //b
        {
            set=true;
            if (table.MakeUpper()==_T("TUBE")) set=false;
            txt->Show(set);
            ctrl->Show(set);
        }

        if (i>1)    //t,s
        {
            set=ChkHol->GetValue();
            if (table.MakeUpper()==_T("ISEC")) set=true;
            if (i==3 && table.MakeUpper()==_T("TUBE")) set=false;
            txt->Show(set);
            ctrl->Show(set);
        }
    }
}


void MatSecDialog::CalcSec()
{
    double b, h, s, t;
    double A(0), I(0), W(0), Av(0);
    wxString table = SecTree->GetItemText(SecTree->GetSelection());

    for (int i=0; i<4; i++)
    {
        wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(900+i, this);
        wxString input=ctrl->GetValue();
        input = sMult(input, ConvUnit(dbSecUnit, lnUnit, _T("1")));  //convert unit

        switch (i)
        {
            case 0: input.ToDouble(&h); break;
            case 1: input.ToDouble(&b); break;
            case 2: input.ToDouble(&t); break;
            case 3: input.ToDouble(&s); break;
        }
    }

    if (table.MakeUpper()==_T("RECT"))
    {
        A=b*h;
        I=b*pow(h,3)/12;
        W=I/(h/2);
        Av=A/1.5;

        if (ChkHol->GetValue())
        {
            double bi=(b-2*s);
            double hi=(h-2*t);
            A-=(bi*hi);
            I-=(bi*pow(hi,3)/12);
            W=I/(h/2);
            Av=A*(b*s)/(b*s+h*t);
        }
    }

    if (table.MakeUpper()==_T("ISEC"))
    {
        double bi=b-s;
        double hi=h-2*t;
        A=b*h-(bi*hi);
        I=(b*pow(h,3)-bi*pow(hi,3))/12;
        W=I/(h/2);
        Av=(h-t)*s;

        if (ChkRot->GetValue())
        {
            hi=h-t;
            bi=b-2*s;
            A=h*b-(hi*bi);
            I=(2*s*pow(h,3)+bi*pow(t,3))/12;
            W=I/(h/2);
            Av=2*h*s;
        }
    }

    if (table.MakeUpper()==_T("TUBE"))
    {
        double pi=3.1415926;
        A=pi/4*pow(h,2);
        I=pi/64*pow(h,4);
        W=I/(h/2);
        Av=A/2;

        if (ChkHol->GetValue())
        {
            double hi=(h-2*t);
            A-=pi/4*pow(hi,2);
            I-=pi/64*pow(hi,4);
            W=I/(h/2);
            Av=A/2;
        }
    }

    if (A*W*I*Av>0)
    {
        for (int i=0; i<4; i++)
        {
            double val(0);
            switch (i)
            {
                case 0: val=A; break;
                case 1: val=I; break;
                case 2: val=W; break;
                case 3: val=Av; break;
            }
            wxString rStr;
            rStr.Printf(_T("%1.2e"), val);

            wxTextCtrl *ctrl = (wxTextCtrl*) FindWindowById(1002+i, this);
            ctrl->ChangeValue(rStr);
        }
    }
}


//----------------- defined section drawing canvas -----------------
BEGIN_EVENT_TABLE(MatSecDialog::SecGraph, wxScrolledWindow)
    EVT_PAINT(MatSecDialog::SecGraph::OnPaint)
    EVT_SIZE(MatSecDialog::SecGraph::OnSize)

END_EVENT_TABLE()

void MatSecDialog::SecGraph::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);

    //get window dimensions
    wxSize sz = GetClientSize();
    wxRect bounds(0, 0, sz.x, sz.y);
    dc.Clear();
    dc.DrawRectangle(bounds);

    //keep it quadratical
    bounds.x+=bounds.width/2;
    bounds.y+=bounds.height/2;
    if (bounds.height>bounds.width)
        bounds.height=bounds.width;
    else bounds.width=bounds.height;

    switch (type)
    {
        case 0 : DrawRect(dc, bounds, false, false); break;
        case 1 : DrawRect(dc, bounds, false, true); break;
        case 2 : DrawRect(dc, bounds, true, false); break;
        case 3 : DrawRect(dc, bounds, true, true); break;
        case 4 : DrawIsec(dc, bounds, false); break;
        case 5 : DrawIsec(dc, bounds, true); break;
        case 6 : DrawTube(dc, bounds, false); break;
        case 7 : DrawTube(dc, bounds, true); break;
    }

}


void MatSecDialog::SecGraph::OnSize(wxSizeEvent& event)
{
    Refresh();
}


void MatSecDialog::SecGraph::SetType(wxString sec, bool hollow, bool rot)
{
    if (sec.MakeUpper()==_T("RECT"))
        if (!hollow)
        {
            if (!rot) type=0; else type=1;
        }
        else
        {
            if (!rot) type=2; else type=3;
        }

    if (sec.MakeUpper()==_T("ISEC"))
        if (!rot) type=4; else type=5;

    if (sec.MakeUpper()==_T("TUBE"))
        if (!hollow) type=6; else type=7;

    Refresh();
}


void MatSecDialog::SecGraph::DrawRect(wxDC& dc, wxRect bounds, bool hollow, bool rot)
{
    int x0 = bounds.x;
    int y0 = bounds.y;

    int width, height, sf;
    if (!rot)
    {
        height=int(bounds.height*0.62);
        width=int(bounds.height*0.38);
        sf=int(0.08*height);
    }
    else
    {
        width=int(bounds.width*0.62);
        height=int(bounds.width*0.38);
        sf=int(0.08*width);
    }

    dc.SetPen(wxPen(wxColour(*wxBLACK),2));
    dc.DrawRectangle(x0-width/2, y0-height/2, width, height);

    dc.SetPen(wxPen(wxColour(*wxBLACK),1));
    DrawDim(dc, wxPoint(x0-width/2, y0+height/2), width, sf, _T("b"), 0);
    DrawDim(dc, wxPoint(x0+width/2, y0+height/2), height, sf, _T("h"), 1);

    if (hollow)
    {
        int t = int(sf*1.25);
        dc.DrawRectangle(x0-width/2+t, y0-height/2+t, width-(2*t), height-(2*t));
        DrawDim(dc, wxPoint(x0-width/2, y0-height/2-3*sf), t, sf, _T("s"), 0);
        DrawDim(dc, wxPoint(x0+width/2-t, y0-height/2-3*sf), t, sf, _T("s"), 0);
        DrawDim(dc, wxPoint(x0-width/2-3*sf, y0+height/2), t, sf, _T("t"), 1);
        DrawDim(dc, wxPoint(x0-width/2-3*sf, y0-height/2+t), t, sf, _T("t"), 1);
    }
}


void MatSecDialog::SecGraph::DrawIsec(wxDC& dc, wxRect bounds, bool rot)
{
    int x0 = bounds.x;
    int y0 = bounds.y;

    if (!rot)
    {
        int height = int(bounds.height*0.62);
        int width = int(bounds.height*0.38);
        int t = int(0.08*height);

        dc.SetPen(wxPen(wxColour(*wxBLACK),2));
        dc.DrawLine(x0-t/2, y0-height/2+t, x0-t/2, y0+height/2-t);
        dc.DrawLine(x0+t/2, y0-height/2+t, x0+t/2, y0+height/2-t);
        dc.DrawRectangle(x0-width/2, y0-height/2, width, t);
        dc.DrawRectangle(x0-width/2, y0+height/2-t, width, t);

        int sf = t;
        dc.SetPen(wxPen(wxColour(*wxBLACK),1));
        DrawDim(dc, wxPoint(x0-width/2, y0+height/2), width, sf, _T("b"), 0);
        DrawDim(dc, wxPoint(x0+width/2, y0+height/2), height, sf, _T("h"), 1);
        DrawDim(dc, wxPoint(x0-t/2, y0-height/2-3*sf), t, sf, _T("s"), 0);
        DrawDim(dc, wxPoint(x0-width/2-3*sf, y0+height/2), t, sf, _T("t"), 1);
        DrawDim(dc, wxPoint(x0-width/2-3*sf, y0-height/2+t), t, sf, _T("t"), 1);
    }
    else
    {
        int width = int(bounds.width*0.62);
        int height = int(bounds.width*0.38);
        int t = int(0.08*width);

        dc.SetPen(wxPen(wxColour(*wxBLACK),2));
        dc.DrawLine(x0-width/2+t, y0+t/2, x0+width/2-t, y0+t/2);
        dc.DrawLine(x0-width/2+t, y0-t/2, x0+width/2-t, y0-t/2);
        dc.DrawRectangle(x0-width/2, y0-height/2, t, height);
        dc.DrawRectangle(x0+width/2-t, y0-height/2, t, height);

        int sf = t;
        dc.SetPen(wxPen(wxColour(*wxBLACK),1));
        DrawDim(dc, wxPoint(x0-width/2, y0+height/2), width, sf, _T("b"), 0);
        DrawDim(dc, wxPoint(x0+width/2, y0+height/2), height, sf, _T("h"), 1);
        DrawDim(dc, wxPoint(x0-width/2, y0-height/2-3*sf), t, sf, _T("s"), 0);
        DrawDim(dc, wxPoint(x0+width/2-t, y0-height/2-3*sf), t, sf, _T("s"), 0);
        DrawDim(dc, wxPoint(x0-width/2-3*sf, y0+t/2), t, sf, _T("t"), 1);
    }
}


void MatSecDialog::SecGraph::DrawTube(wxDC& dc, wxRect bounds, bool hollow)
{
    int x0 = bounds.x;
    int y0 = bounds.y;

    int radius=int(bounds.height*0.25);
    int sf=int(0.16*radius);

    dc.SetPen(wxPen(wxColour(*wxBLACK),2));
    dc.DrawCircle(x0, y0, radius);

    dc.SetPen(wxPen(wxColour(*wxBLACK),1));
    DrawDim(dc, wxPoint(x0+radius, y0+radius), radius*2, sf, _T("h"), 1);

    if (hollow)
    {
        int t = int(sf*1.25);
        dc.DrawCircle(x0, y0, radius-t);
        DrawDim(dc, wxPoint(x0-radius-3*sf, y0-radius+t), t, sf, _T("t"), 1);
    }
}


void MatSecDialog::SecGraph::DrawDim(wxDC& dc, wxPoint pos, int len, int sf, wxString txt, bool rot)
{
    wxPoint from(pos), to, d1, d2, tpos;
    double angle;

    if (!rot)
    {
        from.y+=2*sf;
        to=from; to.x+=len;
        d1.x=0; d1.y=sf/2;
        d2.x=+sf/3; d2.y=-sf/3;
        tpos=from; tpos.x+=int(len/2-0.2*sf); tpos.y-=int(sf*1.8);
        angle=0;
    }

    else
    {
        from.x+=2*sf;
        to=from; to.y-=len;
        d1.x=sf/2; d1.y=0;
        d2.x=sf/3; d2.y=sf/3;
        tpos=from; tpos.y-=int(len/2-0.2*sf); tpos.x-=int(sf*1.8);
        angle=90;
    }

    dc.DrawLine(from.x, from.y, to.x, to.y);

    dc.DrawLine(from.x+d1.x, from.y+d1.y, from.x-d1.x, from.y-d1.y);
    dc.DrawLine(from.x+d2.x, from.y+d2.y, from.x-d2.x, from.y-d2.y);
    dc.DrawLine(to.x+d1.x, to.y+d1.y, to.x-d1.x, to.y-d1.y);
    dc.DrawLine(to.x+d2.x, to.y+d2.y, to.x-d2.x, to.y-d2.y);

    wxFont txtFont(*wxNORMAL_FONT);
    txtFont.SetPointSize(sf);
    dc.SetFont(txtFont);
    dc.DrawRotatedText(txt, tpos.x, tpos.y, angle);
}



//---------------- settings dialog -------------------------
BEGIN_EVENT_TABLE(SettingsDialog, wxDialog)
    EVT_BUTTON(ID_BT_OK, SettingsDialog::OnClose)
    EVT_BUTTON(ID_BT_ESC, SettingsDialog::OnClose)
    EVT_BUTTON(ID_BT_LF, SettingsDialog::OnSetLF)
    EVT_BUTTON(ID_BT_MAT, SettingsDialog::OnSetDB)
    EVT_BUTTON(ID_BT_SEC, SettingsDialog::OnSetDB)

END_EVENT_TABLE()

SettingsDialog::SettingsDialog(wxFrame *parent, wxWindowID id, const wxString &title, wxString file)
        : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxColour(*wxWHITE));
    wxPoint pos = wxGetMousePosition();
    SetSize(pos.x, pos.y, 200, 200);

    //check box header
    ChkHd = new wxCheckBox(this, ID_CHK, _T("print header"), wxDefaultPosition, wxSize(220,30));
    ChkHd->SetValue(true);

    //text control header
    TcHd = new wxTextCtrl(this, -1, _T(""), wxDefaultPosition, wxSize(250,60), wxTE_MULTILINE);

    //combo box force/len units
    wxPanel *u_panel = new wxPanel(this, -1, wxDefaultPosition, wxSize(250,50));
    new wxStaticText(u_panel, -1, _T("Force Units:"), wxPoint(0,0), wxSize(90,20));
    new wxStaticText(u_panel, -1, _T("Length Units:"), wxPoint(100,0), wxSize(90,20));

    wxArrayString units;
    units.Add(_T("N"));
    units.Add(_T("kN"));
    units.Add(_T("kip"));
    CbFc = new wxComboBox(u_panel, -1, _T("kN"), wxPoint(0,20), wxSize(60,25), units, wxCB_READONLY);

    units.Empty();
    units.Add(_T("mm"));
    units.Add(_T("cm"));
    units.Add(_T("m"));
    units.Add(_T("in"));
    units.Add(_T("ft"));
    CbLn = new wxComboBox(u_panel, -1, _T("m"), wxPoint(100,20), wxSize(60,25), units, wxCB_READONLY);

    //button load factors
    wxButton *BtLF = new wxButton(this, ID_BT_LF, _T("LF"), wxDefaultPosition, wxSize(35,25));

    wxBoxSizer *H1sizer = new wxBoxSizer(wxHORIZONTAL);
    H1sizer->Add(u_panel, 1);
    H1sizer->Add(BtLF, 0, wxALIGN_BOTTOM | wxLEFT, 12);

    //text control mat/sec database
    TcMat = new wxTextCtrl(this, -1, _T(""), wxPoint(0,20), wxSize(150,25));
    wxButton *BtMat = new wxButton(this, ID_BT_MAT, _T("Mat"), wxDefaultPosition, wxSize(35,25));
    wxBoxSizer *H2sizer = new wxBoxSizer(wxHORIZONTAL);
    H2sizer->Add(TcMat, 1, wxRIGHT, 12);
    H2sizer->Add(BtMat, 0);

    TcSec = new wxTextCtrl(this, -1, _T(""), wxPoint(0,20), wxSize(150,25));
    wxButton *BtSec = new wxButton(this, ID_BT_SEC, _T("Sec"), wxDefaultPosition, wxSize(35,25));
    wxBoxSizer *H3sizer = new wxBoxSizer(wxHORIZONTAL);
    H3sizer->Add(TcSec, 1, wxRIGHT | wxTOP, 12);
    H3sizer->Add(BtSec, 0, wxTOP, 12);

    //buttons
    wxBoxSizer *BtSizer = new wxBoxSizer(wxHORIZONTAL);
    BtSizer->Add(new wxButton( this, ID_BT_OK, _T("OK"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);
    BtSizer->Add(new wxButton( this, ID_BT_ESC, _T("Cancel"), wxDefaultPosition, wxSize(60,25)), 0, wxALL, 10);

    //layout
    wxBoxSizer *Vsizer = new wxBoxSizer(wxVERTICAL);
    Vsizer->Add(ChkHd, 0,  wxALIGN_LEFT | wxRIGHT | wxLEFT | wxTOP, 20);
    Vsizer->Add(TcHd, 1, wxEXPAND | wxRIGHT | wxLEFT , 20);
    Vsizer->Add(H1sizer, 0,  wxEXPAND | wxALL, 20);
    Vsizer->Add(new wxStaticText(this, -1, _T("Material/Section Database:"), wxDefaultPosition, wxSize(200,20)), 0,  wxRIGHT | wxLEFT, 20);
    Vsizer->Add(H2sizer, 0,  wxEXPAND | wxRIGHT | wxLEFT, 20);
    Vsizer->Add(H3sizer, 0,  wxEXPAND | wxRIGHT | wxLEFT, 20);
    Vsizer->Add(BtSizer, 0, wxALIGN_CENTER | wxALL, 20);

    SetSizer(Vsizer);
    Vsizer->SetSizeHints(this);

    //read or create file, set defaults
    if (!wxFile::Exists(file)) CreateDefaultFile(file);
    ReadXmlFile(file);
    xmLoc = file;
}


void SettingsDialog::OnClose(wxCommandEvent &event)
{
    if (event.GetId()==ID_BT_OK) ChangeXmlFile();
    Close(TRUE);
}


void SettingsDialog::OnSetLF(wxCommandEvent& event)
{
    wxString factors;
    LoadFactorDialog *dialog = new LoadFactorDialog((wxFrame*) this, -1, _T("Set Load Factors"), ldFac);
    if (dialog->ShowModal()) factors = dialog->GetFactors();

    if (!factors.IsEmpty()) ldFac=factors;
    else if (!ldFac.IsEmpty()) ldFac.Empty();
}


void SettingsDialog::OnSetDB(wxCommandEvent& event)
{
    int id = event.GetId();

    if (id==ID_BT_MAT)
    {
        wxString file = TcMat->GetValue();
        wxFileDialog *openFileDialog = new wxFileDialog(this, _T("Choose Material Database"), wxFileName(file).GetPath(), wxFileName(file).GetFullName(), _T("*.xml"), wxFD_OPEN);
        if (openFileDialog->ShowModal() == wxID_OK) TcMat->ChangeValue(openFileDialog->GetPath());
    }

    if (id==ID_BT_SEC)
    {
        wxString file = TcSec->GetValue();
        wxFileDialog *openFileDialog = new wxFileDialog(this, _T("Choose Section Database"), wxFileName(file).GetPath(), wxFileName(file).GetFullName(), _T("*.xml"), wxFD_OPEN);
        if (openFileDialog->ShowModal() == wxID_OK) TcSec->ChangeValue(openFileDialog->GetPath());
    }
}


void SettingsDialog::ReadXmlFile(wxString file)
{
    //check file beforehand otherwise wxwidgets will throw an exception
    wxTextFile *xmlFile = new wxTextFile;
    xmlFile->Open(file);
    wxString head = xmlFile->GetFirstLine();
    xmlFile->Close();

    if (head.Left(5)==_T("<?xml"))
    {
        wxXmlDocument doc;
        if (doc.Load(file, _T("UTF-8"), wxXMLDOC_KEEP_WHITESPACE_NODES))
        {
            wxXmlNode *child = doc.GetRoot()->GetChildren();
            while (child)
            {
                wxString name = child->GetName();

                if (name==_T("header") || name==_T("noheader"))
                {
                    TcHd->Clear();
                    wxXmlNode *subchild = child->GetChildren();
                    while (subchild)
                    {
                        wxString cStr = subchild->GetNodeContent();
                        if (!cStr.IsEmpty()) TcHd->AppendText(cStr+_T("\n"));
                        subchild = subchild->GetNext();
                    }
                    if (name==_T("header")) ChkHd->SetValue(true);
                    else ChkHd->SetValue(false);
                }

                if (name==_T("units"))
                {
                    wxXmlNode *subchild = child->GetChildren();
                    while (subchild)
                    {
                        if (subchild->GetName()==_T("force")) CbFc->SetValue(subchild->GetNodeContent());
                        if (subchild->GetName()==_T("length")) CbLn->SetValue(subchild->GetNodeContent());
                        subchild = subchild->GetNext();
                    }
                }

                if (name==_T("factors"))
                {
                    wxXmlNode *subchild = child->GetChildren();
                    while (subchild)
                    {
                        if (subchild->GetName()==_T("load")) ldFac=subchild->GetNodeContent();
                        subchild = subchild->GetNext();
                    }
                }

                if (name==_T("database"))
                {
                    wxXmlNode *subchild = child->GetChildren();
                    while (subchild)
                    {
                        if (subchild->GetName()==_T("materials")) TcMat->ChangeValue(subchild->GetNodeContent());
                        if (subchild->GetName()==_T("sections")) TcSec->ChangeValue(subchild->GetNodeContent());
                        subchild = subchild->GetNext();
                    }
                }
                child = child->GetNext();
            }
        }
    }

}


void SettingsDialog::ChangeXmlFile()
{
    wxTextFile *xmlFile = new wxTextFile;
    xmlFile->Open(xmLoc);
    xmlFile->Clear();

    wxArrayString xmlBody;
	xmlBody.Add(_T("<?xml version=\"1.0\" standalone=\"yes\"?>"));
    xmlBody.Add(_T("<Settings>"));

    wxString head = TcHd->GetValue();
    if (ChkHd->GetValue()) xmlBody.Add(_T("  <header>"));
    else xmlBody.Add(_T("  <noheader>"));
    while (!head.IsEmpty())
    {
        wxString line = head.BeforeFirst(_T('\n'));
        xmlBody.Add(_T("	<line>")+ChkXML(line)+_T("</line>"));
        head=head.AfterFirst(_T('\n'));
    }
    if (ChkHd->GetValue()) xmlBody.Add(_T("  </header>"));
    else xmlBody.Add(_T("  </noheader>"));

    wxString fcUnit = CbFc->GetValue();
    wxString lnUnit = CbLn->GetValue(); ;
    xmlBody.Add(_T("  <units>  "));
    xmlBody.Add(_T("   <force>")+fcUnit+_T("</force>"));
    xmlBody.Add(_T("   <length>")+lnUnit+_T("</length>"));
    xmlBody.Add(_T("  </units> "));

    xmlBody.Add(_T("  <factors> "));
    xmlBody.Add(_T("    <load>")+ldFac+_T("</load>"));
    xmlBody.Add(_T("  </factors>    "));

    wxString dbMat = TcMat->GetValue();
    wxString dbSec = TcSec->GetValue();
    xmlBody.Add(_T("  <database>"));
    xmlBody.Add(_T("    <materials>")+dbMat+_T("</materials>"));
    xmlBody.Add(_T("	<sections>")+dbSec+_T("</sections>"));
    xmlBody.Add(_T("  </database>"));
    xmlBody.Add(_T("</Settings>"));

    for (size_t i=0; i<xmlBody.GetCount(); i++) xmlFile->AddLine(xmlBody[i]);
    xmlFile->Write();
    xmlFile->Close();
}


wxString SettingsDialog::ChkXML(wxString line)
{
    wxString cStr(line);
    cStr.Replace(_T("<"), _T("&lt;"));
    cStr.Replace(_T(">"), _T("&gt;"));
    cStr.Replace(_T("&"), _T("&amp;"));
    cStr.Replace(_T("\""), _T("&quot;"));
    cStr.Replace(_T("'"), _T("&apos;"));
    cStr.Replace(_T("'"), _T("&apos;"));
    cStr.Replace(_T("`"), _T("&apos;"));
    return cStr;
}


void SettingsDialog::CreateDefaultFile(wxString file)
{
    //create xml file
    wxTextFile *xmlFile = new wxTextFile;
    xmlFile->Create(file);

    wxArrayString xmlBody;
	xmlBody.Add(_T("<?xml version=\"1.0\" standalone=\"yes\"?>"));
    xmlBody.Add(_T("<Settings>"));
    xmlBody.Add(_T("  <header>"));
    xmlBody.Add(_T("	<line>cba 0.3.6</line>"));
    xmlBody.Add(_T("	<line>continuous beam analysis</line>"));
    xmlBody.Add(_T("  </header>"));
    xmlBody.Add(_T("  <units>"));
    xmlBody.Add(_T("   <force>kN</force>"));
    xmlBody.Add(_T("   <length>m</length>"));
    xmlBody.Add(_T("  </units>"));
    xmlBody.Add(_T("  <factors>"));
    xmlBody.Add(_T("    <load></load>"));
    xmlBody.Add(_T("  </factors>"));
    xmlBody.Add(_T("  <database>"));
    //changed default database path for debian	
    xmlBody.Add(_T("    <materials>/usr/share/cba/materials.xml</materials>"));
    xmlBody.Add(_T("	<sections>/usr/share/cba/sections.xml</sections>"));
    xmlBody.Add(_T("  </database>"));
    xmlBody.Add(_T("</Settings>"));

    for (size_t i=0; i<xmlBody.GetCount(); i++) xmlFile->AddLine(xmlBody[i]);
    xmlFile->Write();
    xmlFile->Close();
}


wxArrayString SettingsDialog::GetItems()
{
    wxArrayString text;
    wxString head = TcHd->GetValue();
    if (ChkHd->GetValue()) text.Add(head); else text.Add(_T(""));
    text.Add(CbFc->GetValue());
    text.Add(CbLn->GetValue());
    text.Add(ldFac);
    text.Add(TcMat->GetValue());
    text.Add(TcSec->GetValue());
    return text;
}

