#include <memory>
#include <algorithm>
#include <mof/widget/NullView.hpp>
#include <mof/widget/Pager.hpp>
#include <mof/widget/AbstractTextCompiler.hpp>
#include <mof/widget/WidgetView.hpp>
#include <mof/ConsoleIO.hpp>
#include <deque>

namespace mof
{
namespace widget
{
//{{{ PagerView
	class PagerView : public WidgetView
	{
		std::shared_ptr<mof::widget::WidgetView> view_;
		std::shared_ptr<mof::widget::WidgetView> old_view_;
		mof::Vector2D region_;
		//const mof::Vector2D& region_; なんでconstやったん？
		bool visible_;
	public:

		PagerView(const mof::Vector2D& region)
			: region_(region), visible_(true)
		{
			view_ = std::make_shared<mof::widget::NullView>();
			view_->getPositionStream() << getPositionStream();
			view_->getSizeStream() << getSizeStream();//TODO regionを入れる？
			view_->getColorStream() << getColorStream();
		}

		~PagerView()
		{

		}

		FrameNumber show(bool imidiately)
		{
			
			return view_->show(imidiately);
		}
		
		FrameNumber hide(bool imidiately)
		{
			return view_->hide(imidiately);
		}

		FrameNumber focus(bool imidiately)
		{
			return show(imidiately);
		}
		
		FrameNumber blur(bool imidiately)
		{
			return hide(imidiately);
		}
		
		FrameNumber click(bool)
		{
			return 0;
		}
		
		void update()
		{
			getPositionStream().update();
			getSizeStream().update();
			getColorStream().update();
			if (old_view_.get()) old_view_->update();
			view_->update();
		}
		
		void draw() const
		{
			if (old_view_.get()) old_view_->draw();
			view_->draw();
		}

		void setVisible(bool visible)
		{
			visible_ = visible;
			if (old_view_.get()) old_view_->setVisible(visible);
			if (view_.get()) view_->setVisible(visible);
		}

		mof::Vector2D getPreferredSize() const
		{
			return region_;
		}

		FrameNumber swap(std::shared_ptr<mof::widget::WidgetView> view)
		{
			old_view_ = view_;
			view_ = view;
			view_->setVisible(visible_);
			FrameNumber period = view_->show();
			period = max(period, old_view_->hide());

			view_->getPositionStream() << getPositionStream();
			view_->getSizeStream() << view_->getSizeStream().value() << getSizeStream();
			view_->getColorStream() << getColorStream();
			return period;
		}

	
	};
//}}}
//{{{ Impl
    struct Pager::Impl
    {
        std::shared_ptr<AbstractTextCompiler> pCompiler;
		std::deque<WidgetView::ptr> page_queue;
		std::shared_ptr<PagerView> view_;
      
        Impl(const mof::Vector2D& region, const std::shared_ptr<AbstractTextCompiler>& pCompiler)
        : pCompiler(pCompiler), view_(new PagerView(region))
        {
        }
    };
//}}}
//{{{ constructor
    Pager::Pager(const mof::Vector2D& region, const std::shared_ptr<AbstractTextCompiler>& pCompiler)
    : pImpl_(new Impl(region, pCompiler))
    {
		pImpl_->page_queue.push_back(std::make_shared<NullView>());
    }
//}}}
//{{{ destructor
    Pager::~Pager()
    {
    }
//}}}
//{{{ show
    mof::FrameNumber Pager::show(bool imidiately)
    {
        return 0;
    }
//}}}
//{{{ hide
    mof::FrameNumber Pager::hide(bool imidiately)
    {
        return 0;
    }
//}}}
//{{{ getView
    const std::shared_ptr<mof::widget::WidgetView> Pager::getView() const
    {
		return pImpl_->view_;
    }
//}}}
//{{{ getView
    std::shared_ptr<mof::widget::WidgetView> Pager::getView() 
    {
		return pImpl_->view_;
    }
//}}}
//{{{ update 
    void Pager::update() 
    {
		return pImpl_->view_->update();
    }
//}}}
//{{{  addPage
    void Pager::addPage(const tstring& page) 
    {
		pImpl_->page_queue.push_back(pImpl_->pCompiler->compile(page));
    }
//}}}
//{{{ nextPage
    FrameNumber Pager::nextPage() 
    {
		pImpl_->page_queue.pop_front();
		return pImpl_->view_->swap(pImpl_->page_queue.front());
    }
//}}}

}// namespace widget
}// mof
