#include "taquin.h"

#include <fstream>
#include <istream>
#include <string>
#include <cstdlib>
#include <queue>
#include <ostream>

using namespace std;

Taquin::Taquin()
{}
Taquin::~Taquin()
{}

bool Taquin::loadFile(const string& file) {
    ifstream fileStream(file.c_str(), ios::in);
    istream& is = fileStream;
    string line;
    string n;
    string delim = " \t";

    if (!fileStream)
    {
        fileStream.open(file.c_str(), ios::in);
        if (!fileStream)
            return false;
    }

    while (getline(is, line))
    {
        init.cases.push_back(vector<int>());
        for (string::const_iterator i = line.begin(); i != line.end(); ++i)
        {
            int number;

            if (delim.find(*i) == string::npos) {
                n += *i;
                continue;
            }
            if (n.empty())
                continue;

            number = atoi(n.c_str());
            init.cases.back().push_back(number);
            n.clear();
        }
    }
    return true;
}

void Taquin::affichageInit() {
    cout << endl << "--------------------------------" << endl;
    cout << "Affichage du taquin initial" << endl;

    for(int i = 0; i < init.cases.size(); i++)
    {
        for(int j = 0; j < init.cases[i].size(); j++) {
            cout << init.cases[i][j] << "\t";
        }
        cout << endl;
    }
    cout << endl << endl;
}

State Taquin::rechercheAveugle() {
    queue<State> ouvert;
    set<State> ferme;
    ouvert.push(init);

    while(!ouvert.empty()) {
        State s = ouvert.front();

        if (s.isFinal()) {
            return s;
        }
        else {
            ouvert.pop();
            ferme.insert(s);

            s.affichage();
            for(int i = 0; i < 4; i++) {
                State s2 = s.move(i);
                s2.iter = s.iter+1;

                if(!s2.equalsTo(s)) {
                    if(s2.isFinal())
                        return s2;

                    cout << "Mouvement : "  << i<< endl;
                    s2.affichage();

                    bool exists = false;
                    for (set<State>::const_iterator i = ferme.begin(); i != ferme.end(); ++i) {
                        if(s2.equalsTo(*i)) {
                            exists = true;
                            break;
                        }
                    }

                    if(!exists) ouvert.push(s2);
                }
            }
        }
    }
    State e;
    return e;
}

State Taquin::rechercheAStar() {
    vector<State> ouvert;
    vector<State> ferme;
    init.cost = 0;
    ouvert.push_back(init);

    while(!ouvert.empty()) {

        vector<State>::iterator it = ouvert.begin();
        for(vector<State>::iterator i = ouvert.begin(); i != ouvert.end(); i++) {
            if((*it).cost > (*i).cost)
                it = i;
        }
        State e = *it;

        if (e.isFinal())
            return e;
        ouvert.erase(it);
        ferme.push_back(e);
        e.affichage();

        for(int m = 0; m < 4; m++) {
            State next = e.move(m);

             bool etatdansf = false;
             for (vector<State>::const_iterator i = ferme.begin(); i != ferme.end(); ++i) {
                if(next.equalsTo(*i)) {
                    etatdansf = true;
                    break;
                }
             }

             bool etatdanso = false;
             for (vector<State>::const_iterator i = ouvert.begin(); i != ouvert.end(); ++i) {
                 if(next.equalsTo(*i)) {
                    etatdanso = true;
                    break;
                }
             }

             if(!etatdansf && !etatdanso) {
                next.cost = e.cost + 1;
                ouvert.push_back(next);
            }

            if(etatdanso && next.cost+next.heuristique() > e.cost+1+next.heuristique()) {
                next.cost = next.cost = e.cost + 1;
            }

             if(etatdansf && next.cost+next.heuristique() > e.cost+1+next.heuristique()) {
                next.cost = next.cost = e.cost + 1;

                vector<State>::iterator iter2;
                for(vector<State>::iterator i = ferme.begin(); i != ferme.end(); i++) {
                    if(next.equalsTo(*i)){
                        iter2 = i;
                        break;
                    }
                }

                ferme.erase(iter2);
                ferme.push_back(next);
             }
        }
    }
}
