#include <swidget/SFrame.h>
#include <swindow/SGEngine.h>
#include <swindow/SRasterizer.h>
#include <swidget/SIconFactory.h>
#include <sys/time.h>
#include <stdlib.h>

#define YUU_COUNT 1000

#define TEST_YUU 0
#define TEST_LINE 0
#define TEST_CIRCLE 0
#define TEST_WINDINGRULE_EVENODD 1
#define TEST_WINDINGRULE_NONZERO 0
#define TEST_ICON 0

#if TEST_YUU
static SImage* renderNam (int x, int y, 
    unsigned int width, unsigned int height, const SPen& pen) {
    y = y - height;
    SGEngine* engine = new SGEngine();
    engine->scale (1.0, -1.0);
#include  "nam.cpp"
}
static SImage* renderYuu (int x, int y, 
    unsigned int width, unsigned int height, const SPen& pen) {
    y = y - height;
    SGEngine* engine = new SGEngine();
    engine->scale (3.2, -3.2);
#include  "yuu.cpp"
}

static SImage* renderNam2 (int x, int y, 
    unsigned int width, unsigned int height, const SPen& pen) {
    y = y - height;
    SRasterizer* engine = new SRasterizer();
    engine->scale (1.0, -1.0);
#include  "nam.cpp"
}
static SImage* renderYuu2 (int x, int y, 
    unsigned int width, unsigned int height, const SPen& pen) {
    y = y - height;
    x = x;
    SRasterizer* engine = new SRasterizer(8);
    engine->scale (3.2, -3.2);
#include  "yuu.cpp"
}
static SImage* renderZ (int x, int y, 
    unsigned int width, unsigned int height, const SPen& pen) {
    y = y - height;
    x = x;
    SRasterizer* engine = new SRasterizer();
    engine->scale (3.5, -3.5);
#include  "z.cpp"
}
static SImage* renderGasko (int x, int y, 
    unsigned int width, unsigned int height, const SPen& pen) {
    y = y - height;
    x = x;
    SRasterizer* engine = new SRasterizer();
    engine->scale (3.5, -3.5);
#include  "gasko.cpp"
}

#endif

class MyPanel : public SFrame
{
public:
    SImage* nam;
    SImage* yuu;
    SImage* nam2;
    SImage* yuu2;
    SImage* z;
    SImage* gasko;
    MyPanel () {
#if TEST_YUU
        struct timeval stop, start;
        gettimeofday(&start, 0);
        unsigned int NUM = YUU_COUNT;

        setBackground(SColor("Gray"));
        SPen pen(SColor("black"), SColor("white"), 1.0);
        int val = NUM;
        gettimeofday(&start, 0);
        while (val--) {
            nam = renderNam (0, 0, 80, 80, pen);
            if (val > 1) delete nam;
            
        };
        gettimeofday(&stop, 0);
        fprintf (stderr, "%d nam took %lu ms\n", NUM ,
            (stop.tv_sec - start.tv_sec) * 1000 
                + (stop.tv_usec - start.tv_usec) / 1000);

        gettimeofday(&start, 0);
        val = NUM;
        while (val--) {
            yuu = renderYuu (0, 0, 80, 80, pen);
            if (val > 1) delete yuu;
        }
        gettimeofday(&stop, 0);
        fprintf (stderr, "%d yuu took %lu ms\n", NUM ,
            (stop.tv_sec - start.tv_sec) * 1000 
                + (stop.tv_usec - start.tv_usec) / 1000);

        gettimeofday(&start, 0);
        val = NUM;
        while (val--) {
            nam2 = renderNam2 (0, 0, 80, 80, pen);
            if (val > 1) delete nam2;
        };
        gettimeofday(&stop, 0);
        fprintf (stderr, "%d nam2 took %lu ms\n", NUM ,
            (stop.tv_sec - start.tv_sec) * 1000 
                + (stop.tv_usec - start.tv_usec) / 1000);

        gettimeofday(&start, 0);
        val = NUM;
        while (val--) {
            yuu2 = renderYuu2 (0, 0, 80, 80, pen);
            if (val > 1) delete yuu2;
        }
        gettimeofday(&stop, 0);
        fprintf (stderr, "%d yuu2 took %lu ms\n", NUM ,
            (stop.tv_sec - start.tv_sec) * 1000 
                + (stop.tv_usec - start.tv_usec) / 1000);

        gettimeofday(&start, 0);
        val = NUM;
        while (val--) {
            z = renderZ (0, 0, 80, 80, pen);
            if (val > 1) delete z;
        }
        gettimeofday(&stop, 0);
        fprintf (stderr, "%d z took %lu ms\n", NUM ,
            (stop.tv_sec - start.tv_sec) * 1000 
                + (stop.tv_usec - start.tv_usec) / 1000);

        val = NUM;
        while (val--) {
            gasko = renderGasko (0, 0, 80, 80, pen);
            if (val > 1) delete gasko;
        }
        gettimeofday(&stop, 0);
        fprintf (stderr, "%d gasko took %lu ms\n", NUM ,
            (stop.tv_sec - start.tv_sec) * 1000 
                + (stop.tv_usec - start.tv_usec) / 1000);
#endif

        setBackground (SColor("Grey"));
    };
    virtual ~MyPanel() {
    };

    void drawNamYuu(SCanvas* w, int x, int y,
            unsigned int width ,unsigned int height) {
#if TEST_YUU
        w->putImage (80, 80, *nam);
        w->putImage (160, 80, *yuu);
        w->putImage (80, 160, *nam2);
        w->putImage (160, 160, *yuu2);
        w->putImage (240, 160, *z);
        w->putImage (240, 80, *gasko);
#endif
    }

    void drawLines (SCanvas* w, int x, int y,
            unsigned int width ,unsigned int height) {
#if TEST_LINE
        SRasterizer* engine = new SRasterizer(5);
        // SGEngine crashes.
        //SGEngine* engine = new SGEngine();
        // old SGEngine only support translate and scale at beginning. 
        // remove it at end.
        //engine->scale (300, 300);
        //engine->translate(300, 300); 
        engine->beginImage(0, 0, SString());
        engine->moveto(0, 0);
        engine->lineto(160, 160);
        engine->lineto(0, 160);
        SPen pen(SColor("red"), SColor("black"), 20.0);
        engine->stroke(x, y, width, height, pen);
        engine->newpath();
        engine->moveto(180, 0);
        engine->lineto(340, 160);
        engine->lineto(180, 160);
        SPen pen2(SColor("black"), SColor("black"), 20.0);
        engine->stroke(x, y, width, height, pen2);
        engine->newpath();
        engine->moveto(0, 80);
        engine->lineto(340, 80);
        SColor color ("DarkGreen", 0.8);
        SPen pen3(color, SColor("black"), 40.0);
        engine->stroke(x, y, width, height, pen3);
        engine->newpath();
        double p = 0.552284749831;
        engine->scale (300, 300);
        engine->translate(300, 300); 
        engine->moveto(1, 0);
        engine->curveto(1, p,  p, 1, 0, 1);
        engine->curveto(-p, 1, -1, p, -1, 0);
        engine->curveto(-1, -p, -p, -1, 0, -1);
        engine->curveto(p, -1, 1, -p, 1, 0);
        engine->closepath();
        SPen penF(SColor("#4C6CB3", 0.9), SColor("Gray"), 1.0);
        engine->fill(x, y, width, height, penF);
//        SPen penS(SColor("Black", 0.5), SColor("Gray"), 2.0);
//        engine->stroke(x, y, width, height, penS);

        SImage* im = engine->endImage();
        w->putImage (40, 40, *im);
        delete im;
        delete engine;
#endif
    }
    
    
    void drawIcons(SCanvas* w, int x, int y,
          unsigned int width ,unsigned int height) {
#if TEST_ICON
        SIcon* icon = SIconFactory::getIcon("Preview");
        if (icon) {
            SImage im = icon->getImage();
            SVGBase * svgBase = im.getSVGBase();
            if (svgBase) {
                svgBase->setCanvas (w, SColor("Gray"));
                svgBase->render(40, 40, 10.0);
            }
        }
        icon = SIconFactory::getIcon("CheckFinished");
        if (icon) {
            SImage im = icon->getImage();
            SVGBase * svgBase = im.getSVGBase();
            if (svgBase) {
                svgBase->setCanvas (w, SColor("Gray"));
                svgBase->render(280, 40, 10.0);
            }
        }
#endif
    }

    // This is just an approximation of a circle.
    void drawCircle (SCanvas* w, int x, int y,
            unsigned int width ,unsigned int height) {
#if TEST_CIRCLE
        //(4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831
        SRasterizer* engine = new SRasterizer(5);
        //SGEngine* engine = new SGEngine();
        engine->scale (300, 300);
        engine->translate (300, 300);
        double p = 0.552284749831;
        engine->beginImage(100, 100, SString());
        engine->moveto(1, 0);
        engine->curveto(1, p,  p, 1, 0, 1);
        engine->curveto(-p, 1, -1, p, -1, 0);
        engine->curveto(-1, -p, -p, -1, 0, -1);
        engine->curveto(p, -1, 1, -p, 1, 0);
        engine->closepath();
        SPen penF(SColor("#4C6CB3"), SColor("Gray"), 1.0);
        engine->fill(0, 0, 620, 620, penF);
        SPen penS(SColor("Black"), SColor("Gray"), 10.0);
        engine->stroke(0, 0, 620, 620, penS);
        SImage* im = 0;
        im = engine->endImage();
        if (im) {
            fprintf (stderr, "PutImage offScreen=%d\n", im->offScreen);
            w->putImage (100, 100, *im);
            delete im;
        }
        fprintf (stderr, "PutImage finished.\n");
        //for (int i=0; i<100000; i++) {
        //    fprintf (stdout, "%d\n", i);
        //}
        delete engine;
#endif
    }

    // This is just an approximation of a circle.
    void drawWindingRule (SCanvas* w, int x, int y,
            unsigned int width ,unsigned int height) {
#if TEST_WINDINGRULE_NONZERO || TEST_WINDINGRULE_EVENODD
        //(4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831
#if TEST_WINDINGRULE_EVENODD
        SRasterizer* engine = new SRasterizer(5, SRasterizer::EVENODD);
#else
        SRasterizer* engine = new SRasterizer(5, SRasterizer::NONZERO);
#endif
        //SGEngine* engine = new SGEngine();
        engine->scale (150, 150);
        engine->translate (150, 150);
        double p = 0.552284749831;
        engine->beginImage(100, 100, SString());
        engine->moveto(1, 0);
        engine->curveto(1, p,  p, 1, 0, 1);
        engine->curveto(-p, 1, -1, p, -1, 0);
        engine->curveto(-1, -p, -p, -1, 0, -1);
        engine->curveto(p, -1, 1, -p, 1, 0);
        engine->closepath();

        engine->translate (150, 0);
        engine->moveto(1, 0);
        engine->curveto(1, p,  p, 1, 0, 1);
        engine->curveto(-p, 1, -1, p, -1, 0);
        engine->curveto(-1, -p, -p, -1, 0, -1);
        engine->curveto(p, -1, 1, -p, 1, 0);
        engine->closepath();

        engine->translate (-75, 125);
        engine->moveto(1, 0);
        engine->curveto(1,-p, p,-1, 0,-1);
        engine->curveto(-p,-1, -1,-p, -1, 0);
        engine->curveto(-1, p, -p, 1, 0, 1);
        engine->curveto(p, 1, 1, p, 1, 0);
        engine->closepath();

        SPen penF(SColor("#4C6CB3"), SColor("Gray"), 1.0);
        engine->fill(0, 0, 620, 3620, penF);
        SPen penS(SColor("Black"), SColor("Gray"), 10.0);
        engine->stroke(0, 0, 620, 620, penS);
        SImage* im = 0;
        im = engine->endImage();
        if (im) {
            fprintf (stderr, "PutImage offScreen=%d\n", im->offScreen);
            w->putImage (100, 100, *im);
            delete im;
        }
        fprintf (stderr, "PutImage finished.\n");
        //for (int i=0; i<100000; i++) {
        //    fprintf (stdout, "%d\n", i);
        //}
        delete engine;
#endif
    }

    void redraw(SCanvas* w, int x, int y,
          unsigned int width ,unsigned int height) {
        drawWindingRule (w,x,y,width, height);
        drawCircle (w,x,y,width, height);
        drawNamYuu (w,x,y,width, height);
        drawLines (w,x,y,width, height);
        drawIcons (w,x,y,width, height);
    }

    virtual bool windowClose (SWindow* w) {
        exit(0);
        //return true;
    }
};

int
main (int argc, char* argv[])
{
    SAwt awt;
    //SPanel::setAllDoubleBuffered(true);
    MyPanel * panel = new MyPanel();
    panel->setThisDoubleBuffered(true);
    //panel->setBackground(SColor("#7f7f7f"));
    panel->resize (SDimension(800,800));
    panel->show();
    SEventHandler::start();
    return (0);
}

