#include "shellSTD.hpp"

enum {NOPE, SHAPE, COLLISION, LINE, COLOR, SCALE, ROT, SHELL, DISK, LIMIT, FLOOR, CEIL};

//compare two const char* until one reach \0, return false if different
bool cmp(const char* a, const char* b)
{
    int i=0;
    while(a[i] && b[i])
    {
        if(a[i] != b[i])
            return false;
        i++;
    }
    return true;
}


//surcharge de cout
ostream& operator<<(ostream& out, shell& s)
{
    out << "shape : " << endl;
    for(int i=0;i<s.numPoint();i++)
        printPoint(out,s.getPoint(i));

    out << "wireframe : " << endl;
    for(int i=0;i<s.numLine();i++)
        printLine(out,s.getLine(i));

    out << "collision center at : " ;
    printPoint(out,s.getCenter());
    out << " with radius of " << s.getRadius() << endl;
    return out;
}

//surcharge de cin
istream& operator>>(istream& in, shell& s)
{
    char str[80],       //string buffer
          c;            //control char
    int what=0;         //input mode
    float tmp;
    //main loop, until end of file
    while(in)
    {
        //get first character and go back in stream
        //detect if it is a commentary , a keyword or data
        c = 0;
        while (c==' ' || c=='\n' || c==0)
            c = in.get();
        in.unget();
        //now parse the wireframe
        if (c == '[')
        {
            //define keyword
            in >> str;
            if (cmp(str,"[shape]"))
                what=SHAPE;
            else if (cmp(str,"[obj]"))
                what=COLLISION;
            else if (cmp(str,"[line]"))
                what=LINE;
            else if (cmp(str,"[color]"))
                what=COLOR;
            else if (cmp(str,"[scale]"))
                what=SCALE;
            else if (cmp(str,"[rot]"))
                what=ROT;
            else if (cmp(str,"[end]"))
                what=NOPE;
        }
        else if (c=='#')
            //commentary
            while(c!='\n')
                c = in.get();
        else
            //fill with data
            switch(what)
            {
            case SHAPE:
                s.addPoint(loadPoint(in));
                break;
            case COLLISION:
                s.setCenter(loadPoint(in));
                in >> tmp;
                s.setRadius(tmp);
                break;
            case LINE:
                s.addLine(loadLine(in));
                break;
            case COLOR:
                s.setBrush(loadColor(in));
                break;
            case SCALE:
                in >> tmp;
                s.mulS(tmp);
                //s.setRadius( s.getRadius()*tmp );
                break;
            case ROT:
                in >> c >> tmp;
                s.rotX(tmp);
                in >> c >> tmp;
                s.rotY(tmp);
                in >> c >> tmp;
                s.rotZ(tmp);
                in >> c;
                break;
            case NOPE:
                in >> str;
                break;
            }
    }
    return in;
}


/*function*/

shell loadShell(const char *filename)
{
    cout << filename << endl;
    ifstream file(filename);
    shell s;
    file >> s;
    cout << s;
    file.close();
    return s;
}

point loadPoint(istream& in)
{
    char c;
    float x,
           y,
           z;
    in >> c >> x
       >> c >> y
       >> c >> z
       >> c;
    return point(x,y,z);
}

wire loadLine(istream& in)
{
    char c;
    int a,
        b;
    in >> c >> a
       >> c >> b
       >> c;
    return wire(a,b);
}

color loadColor(istream& in)
{
    char c;
    int r,
        g,
        b;
    in >> c >> r
       >> c >> g
       >> c >> b
       >> c;
    return color(r,g,b);
}

void printPoint(ostream& out, point p)
{
    out<<"X: "<<p.getX()<<" Y: "<<p.getY()<<" Z: "<<p.getZ() << endl;
}
void printLine(ostream& out, wire l)
{
    out << "line : " << '(' << l.a << ',' << l.b << ') ';
    printColor(out,l.c);
}
void printColor(ostream& out, color c)
{
    out << " color : " << '(' << (int)c.r  << ',' << (int)c.g << ',' << (int)c.b << ')' << endl;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

istream& operator>>(istream& in, disk& d)
{
    char str[80],       //string buffer
          c;            //control char
    int what=0;         //input mode
    float tmp;
	point p;
	int i;
    //main loop, until end of file
    while(in)
    {
        //get first character and go back in stream
        //detect if it is a commentary , a keyword or data
        c = 0;
        while (c==' ' || c=='\n' || c==0)
            c = in.get();
        in.unget();
        //now parse the wireframe
        if (c == '[')
        {
            //define keyword
            in >> str;
            if (cmp(str,"[shell]"))
                what=SHELL;
            else if (cmp(str,"[disk]"))
                what=DISK;
            else if (cmp(str,"[limit]"))
                what=LIMIT;
            else if (cmp(str,"[scale]"))
                what=SCALE;
            else if (cmp(str,"[floor]"))
                what=FLOOR;
            else if (cmp(str,"[ceil]"))
                what=CEIL;
            else if (cmp(str,"[end]"))
                what=NOPE;
        }
        else if (c=='#')
            //commentary
            while(c!='\n')
                c = in.get();
        else
            //fill with data
            switch(what)
            {
            case SHELL:
				in >> str;
                d.addShell(loadShell(str));
                break;
            case DISK:
				p = loadPoint(in);
				in >> i;
				d.placeShell(i,p);
				printPoint(cout,p);
				cout << i << endl;
                break;
            case FLOOR:
				in >> tmp;
				d.setFloor(tmp);
                break;
            case CEIL:
				in >> tmp;
				d.setCeil(tmp);
                break;
            case LIMIT:
				in >> tmp;
				d.setRadius(tmp);
                break;
            case SCALE:
                in >> tmp;
//                d.scale(tmp);
                break;
            case NOPE:
                in >> str;
                break;
            }
    }
    return in;
}

disk loadDisk(const char* filename)
{
	disk d;
    ifstream file(filename);
    file >> d;
    file.close();
	cout << "size returning "<< d.size() <<endl;
	return d;
}
