/**************************************************************************//**
 * \file            wxslinearmeter.cpp
 * \author    Gary Harris
 * \date        19/4/2010.
 *
 * This file is part of wxSmithKWIC.
 *
 * wxSmithKWIC - an add-on for wxSmith, Code::Blocks' GUI editor.                    \n
 * Copyright (C) 2010 Gary Harris.
 *
 * wxSmithKWIC is free software: you can redistribute it and/or modify
 * it under the terms of the KWIC License
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * KWIC License for more details.
 *
 * You should have received a copy of the KWIC License along with this
 * program.  If not, see <http://www.koansoftware.com/kwic/kwic-license.htm>.
 *
 *****************************************************************************/
#include "wxslinearmeter.h"
#include "wx/KWIC/LinearMeter.h"

namespace
{
    // Loading images from xpm files
#include "images/linmet16.xpm"
#include "images/linmet32.xpm"

    // This code provides basic informations about item and register
    // it inside wxSmith
    wxsRegisterItem<wxsLinearMeter> Reg(
        _T("kwxLinearMeter"),                                         // Class name
        wxsTWidget,                                                            // Item type
        _T("KWIC License"),                                           // License
        _T("Andrea V. & Marco Cavallini"),                   // Author
        _T("m.cavallini@koansoftware.com"),              // Author's email
        _T("http://www.koansoftware.com/kwic/"),        // Item's homepage
        _T("KWIC"),                                                             // Category in palette
        40,                                                                            // Priority in palette
        _T("LinearMeter"),                                               // Base part of names for new items
        wxsCPP,                                                                // List of coding languages supported by this item
        1, 0,                                                                          // Version
        wxBitmap(linmet32_xpm),                                   // 32x32 bitmap
        wxBitmap(linmet16_xpm),                                   // 16x16 bitmap
        true);                                                                        // We do not allow this item inside XRC files
}

/*! \brief Constructor.
 *
 * \param Data wxsItemResData*    Pointer to a resource data object.
 *
 */
wxsLinearMeter::wxsLinearMeter(wxsItemResData *Data) :
    wxsWidget(
        Data,
        &Reg.Info,
        NULL,
        NULL,
        flVariable | flId | flPosition | flSize | flEnabled | flFocused | flHidden | flToolTip | flHelpText | flSubclass | flMinMaxSize),
    m_iValue(0),
    m_iRangeMin(0),
    m_iRangeMax(100),
    m_bHorizontal(true),
    m_bShowVal(true),
    m_bShowLimits(true)
{
}

/*! \brief Destructor.
 */
wxsLinearMeter::~wxsLinearMeter()
{
    for(size_t i = 0; i < m_arrTags.Count(); i++){
        delete m_arrTags[i];
    }
    m_arrTags.Clear();
}

/*! \brief Build the code that creates the control.
 *
 * \return void
 *
 */
void wxsLinearMeter::OnBuildCreatingCode()
{
    switch(GetLanguage())
    {
        case wxsCPP:
        {
            AddHeader(_T("\"wx/KWIC/LinearMeter.h\""), GetInfo().ClassName);
            Codef(_T("%C(%W,%I,%P,%S);\n"));

            // Default range is 0-100.
            if(m_iRangeMin != 0 || m_iRangeMax != 100){
                Codef(_T("%ASetRangeVal(%d, %d);\n"), static_cast<int>(m_iRangeMin), static_cast<int>(m_iRangeMax));
            }
            if(!m_bHorizontal){
                Codef(_T("%ASetOrizDirection(false);\n"));
            }
            if(!m_bShowVal){
                Codef(_T("%AShowCurrent(false);\n"));
            }
            if(!m_bShowLimits){
                Codef(_T("%AShowLimits(false);\n"));
            }
            wxString ss = m_cdActiveBarColour.BuildCode(GetCoderContext());
            if(!ss.IsEmpty()) Codef(_T("%ASetActiveBarColour(%s);\n"), ss.wx_str());
            ss = m_cdPassiveBarColour.BuildCode(GetCoderContext());
            if(!ss.IsEmpty()) Codef(_T("%ASetPassiveBarColour(%s);\n"), ss.wx_str());
            ss = m_cdBorderColour.BuildCode(GetCoderContext());
            if(!ss.IsEmpty()) Codef(_T("%ASetBorderColour(%s);\n"), ss.wx_str());
            ss = m_cdLimitTextColour.BuildCode(GetCoderContext());
            if(!ss.IsEmpty()) Codef(_T("%ASetTxtLimitColour(%s);\n"), ss.wx_str());
            ss = m_cdValueTextColour.BuildCode(GetCoderContext());
            if(!ss.IsEmpty()) Codef(_T("%ASetTxtValueColour(%s);\n"), ss.wx_str());
            ss = m_cdTagColour.BuildCode(GetCoderContext());
            if(!ss.IsEmpty()) Codef(_T("%ASetTagsColour(%s);\n"), ss.wx_str());
            for(size_t i = 0; i < m_arrTags.Count(); i++){
                TagDesc *Desc = m_arrTags[i];
                Codef(_T("\t%AAddTag(%d);\n"), Desc->val);
            }
            ss = GetCoderContext()->GetUniqueName(_T("LinearMeterFont"));
            wxString sFnt = m_fnt.BuildFontCode(ss, GetCoderContext());
            if(sFnt.Len() > 0){
                Codef(_T("%s"), sFnt.wx_str());
                Codef(_T("%ASetTxtFont(%s);\n"), ss.wx_str());
            }
            // Value needs to be set after other params for correct display.
            if(m_iValue){
                Codef(_T("%ASetValue(%d);\n"), static_cast<int>(m_iValue));
            }

            BuildSetupWindowCode();
            break;
        }
        case wxsUnknownLanguage: // fall-through
        default:
            wxsCodeMarks::Unknown(_T("wxsLinearMeter::OnBuildCreatingCode"), GetLanguage());
    }
}

/*! \brief Build the code that creates the control preview.
 *
 * \param parent wxWindow*    The parent window.
 * \param flags long                    Flags used when creating the preview.
 * \return wxObject                        The control preview object.
 *
 */
wxObject *wxsLinearMeter::OnBuildPreview(wxWindow *parent, long flags)
{
    kwxLinearMeter *preview = new kwxLinearMeter(parent, GetId(), Pos(parent), Size(parent));

    // Default range is 0-100.
    if(m_iRangeMin != 0 || m_iRangeMax != 100){
        preview->SetRangeVal(m_iRangeMin, m_iRangeMax);
    }
    if(!m_bHorizontal){
        preview->SetOrizDirection(false);
    }
    if(!m_bShowVal){
        preview->ShowCurrent(false);
    }
    if(!m_bShowLimits){
        preview->ShowLimits(false);
    }
    wxColour clr = m_cdActiveBarColour.GetColour();
    if(clr.IsOk()){
        preview->SetActiveBarColour(clr);
    }
    clr = m_cdPassiveBarColour.GetColour();
    if(clr.IsOk()){
        preview->SetPassiveBarColour(clr);
    }
    clr = m_cdBorderColour.GetColour();
    if(clr.IsOk()){
        preview->SetBorderColour(clr);
    }
    clr = m_cdLimitTextColour.GetColour();
    if(clr.IsOk()){
        preview->SetTxtLimitColour(clr);
    }
    clr = m_cdValueTextColour.GetColour();
    if(clr.IsOk()){
        preview->SetTxtValueColour(clr);
    }
    clr = m_cdTagColour.GetColour();
    if(clr.IsOk()){
        preview->SetTagsColour(clr);
    }
    for(size_t i = 0; i < m_arrTags.Count(); i++){
        TagDesc *Desc = m_arrTags[i];
        preview->AddTag(Desc->val);
    }
    wxFont fnt = m_fnt.BuildFont();
    if(fnt.IsOk()){
        preview->SetTxtFont(fnt);
    }
    // Value needs to be set after other params for correct display.
    if(m_iValue){
        preview->SetValue(m_iValue);
    }

    return SetupWindow(preview, flags);
}

/*! \brief Enumerate the control's custom properties.
 *
 * \param Flags long    Flags used when creating the control.
 * \return void
 *
 */
void wxsLinearMeter::OnEnumWidgetProperties(cb_unused long Flags)
{
    WXS_LONG(wxsLinearMeter, m_iValue, _("Value"), _T("value"), 0)
    WXS_BOOL(wxsLinearMeter, m_bShowVal, _("Show Value"), _T("show_value"), true)
    WXS_LONG(wxsLinearMeter, m_iRangeMin, _("Range Minimum"), _T("range_min"), 0)
    WXS_LONG(wxsLinearMeter, m_iRangeMax, _("Range Maximum"), _T("range_max"), 100)
    WXS_BOOL(wxsLinearMeter, m_bShowLimits, _("Show Range Values"), _T("show_limit_value"), true)
    WXS_BOOL(wxsLinearMeter, m_bHorizontal, _("Horizontal"), _T("horizontal"), true)
    WXS_COLOUR(wxsLinearMeter, m_cdActiveBarColour, _("Bar Colour"), _T("bar_colour"))
    WXS_COLOUR(wxsLinearMeter, m_cdPassiveBarColour, _("Background Colour"), _T("background_colour"))
    WXS_COLOUR(wxsLinearMeter, m_cdBorderColour, _("Border Colour"), _T("border_colour"))
    WXS_COLOUR(wxsLinearMeter, m_cdLimitTextColour, _("Range Text Colour"), _T("range_text_colour"))
    WXS_COLOUR(wxsLinearMeter, m_cdValueTextColour, _("Value Text Colour"), _T("value_text_colour"))
    WXS_COLOUR(wxsLinearMeter, m_cdTagColour, _("Tag Colour"), _T("tag_colour"))
    WXS_FONT(wxsLinearMeter, m_fnt, _("Font"), _T("font"))
}

// Dynamic properties.
//=================
/*! \brief Add extra control properties.
 *
 * \param Grid wxsPropertyGridManager*    A PropertyGridManager object.
 * \return void
 *
 */
void wxsLinearMeter::OnAddExtraProperties(wxsPropertyGridManager *Grid)
{
    Grid->SelectPage(0);
    m_TagCountId = Grid->GetGrid()->Insert(_("Bar Colour"), new wxIntProperty(_("Number Of Tags"), wxPG_LABEL, (int)m_arrTags.Count()));
    for(int i = 0; i < (int)m_arrTags.Count(); i++){
        InsertPropertyForTag(Grid, i);
    }
    wxsWidget::OnAddExtraProperties(Grid);
}

/*! \brief One of the control's extra properties changed.
 *
 * \param Grid     wxsPropertyGridManager*    A PropertyGridManager object.
 * \param id         wxPGId                                        The property's ID.
 * \return void
 *
 */
void wxsLinearMeter::OnExtraPropertyChanged(wxsPropertyGridManager *Grid, wxPGId id)
{
    Grid->SelectPage(0);
    if(id == m_TagCountId){
        int OldValue = (int)m_arrTags.Count();
        int NewValue = Grid->GetPropertyValueAsInt(id);

        if(NewValue < 0){
            NewValue = 0;
            Grid->SetPropertyValue(id, NewValue);
        }

        if(NewValue > OldValue){
            // We have to generate new entries
            for(int i = OldValue; i < NewValue; i++)
            {
                m_arrTags.Add(new TagDesc());
                InsertPropertyForTag(Grid, i);
            }
        }
        else if(NewValue < OldValue){
            // We have to remove some entries
            for(int i = NewValue;i < OldValue;i++){
                Grid->DeleteProperty(m_arrTags[i]->id);
                delete m_arrTags[i];
            }

            m_arrTags.RemoveAt(NewValue, OldValue - NewValue);
        }

        NotifyPropertyChange(true);
        return;
    }

    for(int i = 0;i < (int)m_arrTags.Count();i++){
        if(HandleChangeInTag(Grid, id, i)) return;
    }
    wxsWidget::OnExtraPropertyChanged(Grid, id);
}

/*! \brief Read XML control data.
 *
 * \param Element     TiXmlElement*    A pointer to the parent node of the XML block.
 * \param IsXRC         bool                        Whether this is an XRC file.
 * \param IsExtra         bool                        Whether the data is extra information not conforming to the XRC standard.
 * \return bool                                            Success or failure.
 *
 */
bool wxsLinearMeter::OnXmlRead(TiXmlElement *Element, bool IsXRC, bool IsExtra)
{
    for(size_t i = 0;i < m_arrTags.Count();i++){
        delete m_arrTags[i];
    }
    m_arrTags.Clear();

//    TiXmlElement *TagElem = Element->FirstChildElement("tags");
//    // Avoid crash if tags element doesn't exist.
//    if(TagElem){
//        for(TiXmlElement *ValElem = TagElem->FirstChildElement();
//                ValElem;
//                ValElem = ValElem->NextSiblingElement())
//        {
//            TagDesc *Desc = new TagDesc;
//            long lVal;
//            wxString sVal(ValElem->GetText(), wxConvUTF8);
//            sVal.ToLong(&lVal);
//            Desc->val = lVal;
//            m_arrTags.Add(Desc);
//        }
//    }
    int i = 1;
    while(1){
        wxString s = wxString::Format(wxT("tag_%d_value"), i);
        TiXmlElement *TagElem = Element->FirstChildElement(s.mb_str());
        if(!TagElem){
            break;
        }

        TagDesc *Desc = new TagDesc;
        long iVal;
        wxString sVal(TagElem->GetText(), wxConvUTF8);
        sVal.ToLong(&iVal);
        Desc->val = iVal;
        m_arrTags.Add(Desc);
        i++;
    }

    return wxsWidget::OnXmlRead(Element, IsXRC, IsExtra);
}

/*! \brief Write XML data.
 *
 * \param Element     TiXmlElement*    A pointer to the parent node of the XML block.
 * \param IsXRC         bool                        Whether this is an XRC file.
 * \param IsExtra         bool                        Whether the data is extra information not conforming to the XRC standard.
 * \return bool                                            Success or failure.
 *
 */
bool wxsLinearMeter::OnXmlWrite(TiXmlElement *Element, bool IsXRC, bool IsExtra)
{
//    TiXmlElement *tags = new TiXmlElement("tags");
//    Element->LinkEndChild(tags);
//
//    for(size_t i = 0;i < m_arrTags.Count();i++){
//        TagDesc *Desc = m_arrTags[i];
//        wxString s = wxString::Format(wxT("tag_%d_value"), i + 1);
//        TiXmlElement *msg = new TiXmlElement(s.mb_str());
//        msg->LinkEndChild(new TiXmlText(wxString::Format(wxT("%d"), Desc->val).mb_str()));
//        tags->LinkEndChild(msg);
//    }
    for(size_t i = 0;i < m_arrTags.Count();i++){
        TagDesc *Desc = m_arrTags[i];
        wxString s = wxString::Format(wxT("tag_%lu_value"), static_cast<unsigned long>(i + 1));
        TiXmlElement *msg = new TiXmlElement(s.mb_str());
        msg->LinkEndChild(new TiXmlText(wxString::Format(wxT("%d"), Desc->val).mb_str()));
        Element->LinkEndChild(msg);
    }

    return wxsWidget::OnXmlWrite(Element, IsXRC, IsExtra);
}

/*! \brief    Insert a new tag value property.
 *
 * \param Grid             wxsPropertyGridManager*    A PropertyGridManager object.
 * \param Position     int                                                The position of this item in the tag array.
 * \return void
 *
 */
void wxsLinearMeter::InsertPropertyForTag(wxsPropertyGridManager *Grid, int Position)
{
    TagDesc *Desc = m_arrTags[Position];
    wxString sTagName = wxString::Format(_("Tag %d Value"), Position + 1);

    Desc->id = Grid->GetGrid()->Insert(_("Bar Colour"), new wxIntProperty(sTagName, wxPG_LABEL, Desc->val));
}

/*! \brief Check whether a tag value property changed.
 *
 * \param Grid             wxsPropertyGridManager*    A PropertyGridManager object.
 * \param id                 wxPGId                                        The property's ID.
 * \param Position     int                                                The position of this item in the tag array.
 * \return bool            True if a change was recorded, false otherwise.
 *
 */
bool wxsLinearMeter::HandleChangeInTag(wxsPropertyGridManager *Grid, wxPGId id, int Position)
{
    TagDesc *Desc = m_arrTags[Position];
    bool Changed = false;

    if(Desc->id == id){
        Desc->val = Grid->GetPropertyValueAsInt(id);
        Changed = true;
    }

    if(Changed){
        NotifyPropertyChange(true);
        return true;
    }

    return false;
}

