#include <math.h>
#include "gfxMR.hpp"

#include <iostream>

class fturtle
{
    protected: //just dont understand why it bug with ftpop
    public:
        ploter * _plot;
        fturtle * _stack;    //stack
        fturtle * _undo;
        int _x,
            _y;
        float _radian;
        Uint8 _color;
        bool _pen;
        virtual void _init(fturtle * turtle)
        {
            _plot = turtle->_plot;
            _stack = turtle->_stack;
            _undo = turtle;
            _x = turtle->_x;
            _y = turtle->_y;
            _radian = turtle->_radian;
            _color = turtle->_color;
            _pen = turtle->_pen;
        }
    public:
        fturtle(int x, int y, ploter & plot)
        {
            _plot = & plot;
            _stack = 0;
            _undo = 0;
            _x = x;
            _y = y;
            _radian = 0;
            _color = 255;
            _pen = true;
        }
        fturtle(int x, int y, ploter * plot)
        {
            _plot = plot;
            _stack = 0;
            _undo = 0;
            _x = x;
            _y = y;
            _radian = 0;
            _color = 255;
            _pen = true;
        }
        fturtle(fturtle * turtle)
        {
            _init(turtle);
        }
        fturtle(fturtle & turtle)
        {
            _init(&turtle);
        }
        //virtual ~fturtle(){}
        virtual void close()
        {
        }
        void operator () ()
        {
            if (_undo)
                (*_undo)();
            close();
        }
};

class ftleft:public fturtle
{

    public:
        ftleft(fturtle * turtle, float radian):fturtle(turtle)
        {
            _radian += radian;
        }
        ftleft(fturtle & turtle, float radian):fturtle(&turtle)
        {
            _radian += radian;
        }
        //~ftleft(){}
};

class ftright:public fturtle
{
    public:
        ftright(fturtle * turtle, float radian):fturtle(turtle)
        {
            _radian -= radian;
        }
        ftright(fturtle & turtle, float radian):fturtle(&turtle)
        {
            _radian -= radian;
        }
        //~ftright(){}
};

class ftfwd:public fturtle
{
    int _radius;
    float _ix,
          _iy;
    void _init(int radius)
    {
        _radius = radius;
        _ix = sin(_radian);
        _iy = cos(_radian);
        _x += (radius * _ix);
        _y += (radius * _iy);
    }
    public:
        ftfwd(fturtle * turtle, int radius):fturtle(turtle)
        {
            _init(radius);
        }
        ftfwd(fturtle & turtle, int radius):fturtle(&turtle)
        {
            _init(radius);
        }
        //~ftfwd(){}
        void close()
        {
            if(_pen)
            {
                float x = _x,
                      y = _y;
                for (int i=0; i<_radius; i++)
                {
                    (*_plot)((int)x,(int)y,_color);
                    x -= _ix;
                    y -= _iy;
                }
            }
        }
};

class ftpen:public fturtle
{
    public:
        ftpen(fturtle * turtle, bool down):fturtle(turtle)
        {
            _pen = down;
        }
        ftpen(fturtle & turtle, bool down):fturtle(&turtle)
        {
            _pen = down;
        }
        //~ftpen(){}
};

class ftcolor:public fturtle
{
    public:
        ftcolor(fturtle * turtle, Uint8 color):fturtle(turtle)
        {
            _color = color;
        }
        ftcolor(fturtle & turtle, Uint8 color):fturtle(&turtle)
        {
            _color = color;
        }
        //~ftcolor(){}
};

class ftpush:public fturtle
{
    void _init()
    {
        _stack = _undo;
    }
    public:
        ftpush(fturtle * turtle):fturtle(turtle) { _init();}
        ftpush(fturtle & turtle):fturtle(&turtle) { _init(); }
        //~ftpush(){}
};

class ftpop:public fturtle
{
    protected:
    void _init()
    {
        if(_stack)
        {
            _plot = _stack->_plot;
            _x = _stack->_x;
            _y = _stack->_y;
            _radian = _stack->_radian;
            _color = _stack->_color;
            _pen = _stack->_pen;
            _stack = _stack->_stack;
        }
    }
    public:
        ftpop(fturtle * turtle):fturtle(turtle) { _init();}
        ftpop(fturtle & turtle):fturtle(&turtle) { _init(); }
        //~ftpop(){}
};


class gcfturtle
{
    gcfturtle * _back;
    fturtle * _data;
    public:
        gcfturtle(gcfturtle * back, fturtle * data)
        {
            _back = back;
            _data = data;
        }
        gcfturtle(fturtle * data)
        {
            _back = 0;
            _data = data;
        }
        gcfturtle()
        {
            _back = 0;
            _data = 0;
        }
        ~gcfturtle()
        {
            if (_back)
                delete _back;
            if (_data)
                delete _data;
        }
        fturtle * data()
        {
            return _data;
        }
        gcfturtle * back()
        {
            return _back;
        }
        gcfturtle * add(fturtle * data)
        {
            return new gcfturtle(this,data);
        }
};