package org.artisanlogiciel.games.stl;

import org.artisanlogiciel.games.maze.Brick;
import org.artisanlogiciel.games.maze.LabyModel;

import java.io.IOException;
import java.io.OutputStream;

public class Wall3dStream
{

    String name;
    LabyModel provider;
    OutputStream stream;

    Maze3dParams params;

    /**
     *
     * @param name
     * @param provider
     * @param stream
     * @param params
     */
    public Wall3dStream(String name, LabyModel provider, OutputStream stream, Maze3dParams params)
    {
        this.name = name;
        this.provider = provider;
        this.stream = stream;
        this.params = params;
    }

    private void writeWall3D(Wall3d wall3d)
            throws IOException
    {
        stream.write(wall3d.toString().getBytes());
    }

    public void stream() throws IOException {
        int width = provider.getWidth();
        int height = provider.getHeight();

        int xl = params.getXl();
        int yl = params.getYl();
        int zl = params.getZl();
        boolean reverse = params.isReverse();

        // WARNING DOWN - UP reversed ( in 2D Y is oriented to lower, in 3D it
        // is to upper ).
        stream.write(("solid " + name + "\n").getBytes());
        for (int x = 0; x < width; x++) {
            short walls = provider.getWalls(x, 0);
            if ((walls & Brick.UP) != 0) {
                writeWall3D(new Wall3d(params.getSouth(), x * xl, 0, 0));
            }
            if ((walls & Brick.LEFT) != 0) {
                writeWall3D(new Wall3d(params.getWest(), x * xl, 0, 0));
            }
        }

        for (int y = 0; y < height; y++) {
            short walls = provider.getWalls(0, y);
            if ((walls & Brick.LEFT) != 0) {
                writeWall3D(new Wall3d(params.getWest(), 0, y * yl, 0));
            }
            for (int x = 0; x < width; x++) {
                // south and east
                walls = provider.getWalls(x, y);
                if ((walls & Brick.DOWN) != 0) {
                    writeWall3D(new Wall3d(params.getNorth(), x * xl, y * yl, 0));
                }
                if ((walls & Brick.RIGHT) != 0) {
                    writeWall3D(new Wall3d(params.getEast(), x * xl, y * yl, 0));
                }
                short path = provider.getPath(x, y);

                // where resolved path is leaked to stl model.
                Wall3d ground = reverse ? params.getLowGround() : params.getHighGround();
                if ((path & LabyModel.SOLVED) == LabyModel.SOLVED)
                //		if ( (walls & ( Brick.GOAL | Brick.ENTRY ) ) == 0 )
                {
                    // if ( ( (x+y) % 2) == 0 )
                    ground = reverse ? params.getHighGround() : params.getLowGround();
                }
                writeWall3D(new Wall3d(ground, x * xl, y * yl, 0));
            }
        }

        stream.write("endsolid wall\n\n".getBytes());

        stream.flush();
    }
}
