package org.artisanlogiciel.games.maze;

import org.artisanlogiciel.games.maze.model.HalfSquareModelCreator;
import org.artisanlogiciel.games.maze.model.HalfSquareRasterModel;
import org.artisanlogiciel.games.maze.persist.HalfSquareRasterModelPersistRaw;
import org.artisanlogiciel.games.maze.persist.MazePersistRaw;
import org.artisanlogiciel.games.maze.persist.MazePersistWorldEdit;
import org.artisanlogiciel.games.stl.Maze3dParams;
import org.artisanlogiciel.games.stl.Wall3dStream;
import org.artisanlogiciel.graphics.Drawing;
import org.artisanlogiciel.graphics.SvgWriter;
import org.artisanlogiciel.osm.OsmReader;
import org.artisanlogiciel.osm.convert.OsmToDrawing;

import java.io.*;

public class Maze {

    protected LabyLayers layers = new LabyLayers();
    protected LabyModel model;
    int layer = 0;

    protected MazeParams params = null;

    public Maze(LabyModel model)
    {
        this.model = model;
    }

    public MazeParams getParams() {
        return params;
    }

    protected void refresh()
    {
        addStatus("refresh...");
    }

    public boolean isStatusEnable() {
        return false;
    }

    public void addDrawing(Drawing drawing, boolean add)
    {
        // FIXME in non graphical case
        // does nothing yet
    }

    public void setStatusEnable(boolean statusEnable) {
        // does nothing
    }

    protected void addStatus(String status)
    {
        System.out.println(status);
    }

    // to allow to log / write somewher into screen...
    public void writeSentence(String pSentence) {
        // TODO
        addStatus(pSentence);
    }

    void writeError(String pError) {
        System.err.println(pError);
    }


    public void saveWorldEdit() {
        File outfile = getFileForExtension("we");
        if (!outfile.exists()) {
            addStatus("Saving we to " + outfile + " ...");
            try {
                FileOutputStream out = new FileOutputStream(outfile);
                new MazePersistWorldEdit(layers).streamOut("we", out);
                out.close();
                addStatus("... Done.");
            } catch (IOException io) {
                io.printStackTrace(System.err);
            }
        } else {
            addStatus("we file " + outfile + " already exists");
        }

    }

    public void saveStl(MazeParamsFixed params, Maze3dParams wallparams) {
        File outfile = getFileForExtension(params,"stl");
        if (!outfile.exists()) {
            addStatus("Saving stl to " + outfile + " ...");
            try {
                FileOutputStream out = new FileOutputStream(outfile);
                new Wall3dStream(params.getName(), model, out, wallparams).stream();
                out.close();
                addStatus("... Done.");
            } catch (IOException io) {
                io.printStackTrace(System.err);
            }
        } else {
            addStatus("stl file " + outfile + " already exists");
        }

    }

    public void saveRaw(MazeParamsFixed params)
    {
        save(params,model);
    }

    void save(MazeParamsFixed params, LabyModel model) {
        File outfile = getFileForExtension(params,"raw");
        if (!outfile.exists()) {
            addStatus("Saving to " + outfile + " ...");
            try {
                FileOutputStream out = new FileOutputStream(outfile);
                MazePersistRaw persist = new MazePersistRaw(model);
                persist.streamOut("raw", out);
                out.flush();
                out.close();
                addStatus("... Done.");
            } catch (IOException io) {
                io.printStackTrace(System.err);
            }
        } else {
            addStatus("" + outfile + " already exists");
        }
    }

    public void saveImc() {
        Drawing d = createDrawing();

        if (d != null) {
            File outfile = getFileForExtension("imc");
            writeSentence("Saving to " + outfile + " ...");
            try {
                DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile));
                d.saveLinesKompressed(out);
                out.flush();
                out.close();
                writeSentence("... Done.");
            } catch (IOException io) {
                io.printStackTrace(System.err);
            }
        }
    }

    File getFileForExtension(MazeParams p, final String extension)
    {
        return new File(p.getSaveDir(), p.getName() + "." + extension);
    }

    protected File getFileForExtension(final String extension)
    {
        return getFileForExtension(params,extension);
    }

    public Drawing createDrawing() {
        return new DrawingGenerator(model).createDrawing();
    }

    public void saveSvg() {
        Drawing d = createDrawing();

        if (d != null) {
            File outfile = getFileForExtension("svg");
            writeSentence("Saving to " + outfile + " ...");
            try {
                DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile));
                SvgWriter writer = new SvgWriter(d.getInternLines());
                writer.writeTo(out);
                out.flush();
                out.close();
                writeSentence("... Done.");
            } catch (IOException io) {
                io.printStackTrace(System.err);
            }
        } else {
            writeError("drawing creation failed");
        }
    }

    public void saveText() {
        File outfile = getFileForExtension("txt");
        writeSentence("Saving to " + outfile + " ...");
        try {
            DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile));
            out.write(model.toLabyMap().toString().getBytes());
            out.flush();
            out.close();
            writeSentence("... Done.");
        } catch (IOException io) {
            io.printStackTrace(System.err);
        }
    }

    public void saveHalfSquerRaw() {
        String extension = "sraw";
        File outfile = getFileForExtension(extension);
        writeSentence("Saving to " + outfile + " ...");
        try {
            // TODO
            HalfSquareRasterModelPersistRaw persistRaw = new HalfSquareRasterModelPersistRaw(new HalfSquareModelCreator().createFromMovesProvider(model));
            DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile));
            persistRaw.streamOut(extension,out);
            out.write(model.toLabyMap().toString().getBytes());
            out.flush();
            out.close();
            writeSentence("... Done.");
        } catch (IOException io) {
            io.printStackTrace(System.err);
        }
    }

    protected void setModel( LabyModel model)
    {
        this.model = model;
        layers.addLabyModel(layer, model);
    }

    public int setLayer(int x)
    {
        addStatus("set layer " + x);
        LabyModel layermodel = layers.getLayer(x);
        if ( layermodel == null )
        {
            // clone it
            model = new LabyModel(model);
            layers.addLabyModel(x, model);
        }
        else
        {
            model = layermodel;
        }
        layer = x;
        refresh();
        return layer;
    }

    public void loadWorldEdit(boolean add) {

        File infile = new File(params.getSaveDir(), params.getName() + ".we");
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(infile);
            LabyLayers newLayers = new MazePersistWorldEdit().parseInputStream("we",inputStream);
            if ( ! newLayers.isEmpty()) {
                int l = layer;
                for (int i = newLayers.getMin(); i <= newLayers.getMax(); i++) {
                    LabyModel m = newLayers.getLayer(i);
                    if (m != null) {
                        System.out.println("add layer " + l);
                        layers.addLabyModel(l, m);
                        l++;
                    }
                }
                setModel(layers.getLayer(layer));
            }
        } catch (IOException io) {
            io.printStackTrace(System.err);
            addStatus("[ERROR] Can't load " + infile.getAbsolutePath());
        } finally {
            if (inputStream != null) {
                // cleanup
                try {
                    inputStream.close();
                } catch (Exception any) {
                    // don't care really
                }
            }
        }
    }

    public void loadRaw() {
        File infile = new File(params.getSaveDir(), params.getName() + ".raw");
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(infile);
            setModel(new MazePersistRaw().parseInputStream("raw",inputStream));
        } catch (IOException io) {
            io.printStackTrace(System.err);
            addStatus("[ERROR] Can't load " + infile.getAbsolutePath());
        }
        finally
        {
            if (inputStream != null )
            {
                // cleanup
                try {
                    inputStream.close();
                }
                catch (Exception any)
                {
                    // don't care really
                }
            }
        }
    }

    public void loadOsm(boolean add, int mulx, int muly) {
            new Thread() {
                @Override
                public void run() {
                    File infile = new File(params.getSaveDir(), params.getName() + ".osm");
                    FileInputStream inputStream = null;
                    try {
                        // TODO really use InputStream and not pathname
                        OsmReader reader = new OsmReader(infile.getCanonicalPath());
                        reader.read();
                        OsmToDrawing converter = new OsmToDrawing(reader, mulx,muly);
                        Drawing drawing = converter.getDrawing(reader.getWays());
                        setStatusEnable(false);
                        addDrawing(drawing,add);
                        setStatusEnable(true);
                    } catch (IOException io) {
                        io.printStackTrace(System.err);
                        addStatus("[ERROR] Can't load " + infile.getAbsolutePath());
                    } finally {
                        if (inputStream != null) {
                            // cleanup
                            try {
                                inputStream.close();
                            } catch (Exception any) {
                                // don't care really
                            }
                        }
                    }
                }
            }.start();
    }

    public void loadImc(boolean add) {
            new Thread() {
                @Override
                public void run() {
                    File infile = new File(params.getSaveDir(), params.getName() + ".imc");
                    FileInputStream inputStream = null;
                    try {
                        inputStream = new FileInputStream(infile);
                        // TODO
                        // model = new MazePersistRaw().parseInputStream("raw",inputStream);
                        Drawing drawing = new Drawing();
                        drawing.loadLinesExpanded(new DataInputStream(inputStream));
                        setStatusEnable(false);
                        addDrawing(drawing,add);
                        setStatusEnable(true);
                    } catch (IOException io) {
                        io.printStackTrace(System.err);
                        addStatus("[ERROR] Can't load " + infile.getAbsolutePath());
                    } finally {
                        if (inputStream != null) {
                            // cleanup
                            try {
                                inputStream.close();
                            } catch (Exception any) {
                                // don't care really
                            }
                        }
                    }
                }
            }.start();
    }

    public void loadDrawing(boolean add) {
            new Thread() {
                @Override
                public void run() {
                    File infile = new File(params.getSaveDir(), params.getName() + ".drawing");
                    FileInputStream inputStream = null;
                    try {
                        inputStream = new FileInputStream(infile);
                        // TODO
                        // model = new MazePersistRaw().parseInputStream("raw",inputStream);
                        Drawing drawing = new Drawing();
                        drawing.loadLines(new DataInputStream(inputStream));
                        setStatusEnable(false);
                        addDrawing(drawing,add);
                        setStatusEnable(true);
                    } catch (IOException io) {
                        io.printStackTrace(System.err);
                        addStatus("[ERROR] Can't load " + infile.getAbsolutePath());
                    } finally {
                        if (inputStream != null) {
                            // cleanup
                            try {
                                inputStream.close();
                            } catch (Exception any) {
                                // don't care really
                            }
                        }
                    }
                }
            }.start();
    }

}
