#include "stdafx.h"
#include <boost/make_shared.hpp>
#include "NoesisTutorial.h"

#include <ZioLog/ZioLog.h>
#include <ZioLog/ZBLK.h>

// #ifdef _DEBUG
// #define new DEBUG_NEW
// #endif

ZLOGFACILITY("DataBinding");

using namespace Noesis;
using namespace NoesisUtil;

namespace NoesisTutorial {
    //----------------------------------------------------
    // DataBinding NoesisGUI element
    //----------------------------------------------------
    class DataBinding : public UserControl
    {
    private:
        void InitializeComponent()
        {
            __ZBLK__;
            LINFO((__FUNCTION__));
            GUI::LoadComponent(this, FormatResourcePath("DataBinding.xaml").c_str());
        }

    public:
        DataBinding()
        {
            LINFO((__FUNCTION__));
            InitializeComponent();
        }

        virtual ~DataBinding()
        {
            __ZBLK__;
            LINFO((__FUNCTION__));
        }

    public:
        NS_IMPLEMENT_INLINE_REFLECTION(DataBinding, UserControl)
        {
            NsMeta<TypeId>("NoesisTutorial.DataBinding");
        }
    };



    //----------------------------------------------------
    // DataBindingVM
    //----------------------------------------------------
    
    NS_DECLARE_SYMBOL(PointCount);
    NS_DECLARE_SYMBOL(PathLength);
    NS_DECLARE_SYMBOL(Pitch);
    NS_DECLARE_SYMBOL(PathData);

    class DataBindingVM : public BaseComponent, public INotifyPropertyChanged
    {
    public:
        NS_IMPLEMENT_INTERFACE_FIXUP

    public:
        DataBindingVM()
        {
            setupPath();
        }

        void setupPath()
        {
            int yBase = 50;
            m_pitch = (float)m_length / (float)m_count;

            m_pathData = MakePtr<StreamGeometry>();
            StreamGeometryContext context = m_pathData->Open();
            context.BeginFigure(Point(0, yBase), false);

            for (int i = 0; i < m_count; i++) {
                float x = i * m_pitch;
                float y = yBase + (((i % 2) == 0) ? 10 : -10);
                context.LineTo(Point(x, y));
            }
            context.Close();

            _propertyChanged(this, NSS(Pitch));
            _propertyChanged(this, NSS(PathData));
        }

        // From INotifyPropertyChanged
        PropertyChangedEventHandler& PropertyChanged() override { return _propertyChanged; }

    private:
        Ptr<StreamGeometry> m_pathData;
        int m_count = 100;
        int m_length = 300;
        float m_pitch = .0f;

        int GetPointNum() const { return m_count; }
        float GetLength() const { return m_length; }

        void SetPointNum(int num) {
            m_count = num;
            _propertyChanged(this, NSS(PointCount));
            setupPath();
        }
        void SetLength(float w) {
            m_length = w;
            _propertyChanged(this, NSS(PathLength));
            setupPath();
        }

        PropertyChangedEventHandler _propertyChanged;

        NS_IMPLEMENT_INLINE_REFLECTION(DataBindingVM, BaseComponent)
        {
            NsMeta<TypeId>("NoesisTutorial.DataBindingVM");
            NsImpl<INotifyPropertyChanged>();
            NsProp("PointCount", &DataBindingVM::GetPointNum, &DataBindingVM::SetPointNum);
            NsProp("PathLength", &DataBindingVM::GetLength, &DataBindingVM::SetLength);
            NsProp("Pitch", &DataBindingVM::m_pitch);
            NsProp("PathData", &DataBindingVM::m_pathData);
        }
    };

    Ptr<BaseComponent> CreateContext_DataBinding() {
        return MakePtr<DataBindingVM>();
    }

    NOESIS_COMP_REGISTRATION(DataBinding);
    NOESIS_COMP_REGISTRATION(DataBindingVM);
}

