package org.sunflow.core.display;

import java.io.IOException;

import javax.swing.JPanel;

import org.sunflow.core.Display;
import org.sunflow.image.Color;

@SuppressWarnings("serial")
public class ImgPipeDisplay extends JPanel implements Display {
    private int ih;

    /**
     * Render to stdout using the imgpipe protocol used in mental image's
     * imf_disp viewer. http://www.lamrug.org/resources/stubtips.html
     */
    public ImgPipeDisplay() {
    }

    public synchronized void imageBegin(int w, int h, int bucketSize) {
        ih = h;
        outputPacket(5, w, h, Float.floatToRawIntBits(1.0f), 0);
        System.out.flush();
    }

    public synchronized void imagePrepare(int x, int y, int w, int h, int id) {
    }

    public synchronized void imageUpdate(int x, int y, int w, int h, Color[] data, float[] alpha) {
        int xl = x;
        int xh = x + w - 1;
        int yl = ih - 1 - (y + h - 1);
        int yh = ih - 1 - y;
        outputPacket(2, xl, xh, yl, yh);
        byte[] rgba = new byte[4 * (yh - yl + 1) * (xh - xl + 1)];
        for (int j = 0, idx = 0; j < h; j++) {
            for (int i = 0; i < w; i++, idx += 4) {
                int rgb = data[(h - j - 1) * w + i].toNonLinear().toRGB();
                int cr = (rgb >> 16) & 0xFF;
                int cg = (rgb >> 8) & 0xFF;
                int cb = rgb & 0xFF;
                rgba[idx + 0] = (byte) (cr & 0xFF);
                rgba[idx + 1] = (byte) (cg & 0xFF);
                rgba[idx + 2] = (byte) (cb & 0xFF);
                rgba[idx + 3] = (byte) (0xFF);
            }
        }
        try {
            System.out.write(rgba);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized void imageFill(int x, int y, int w, int h, Color c, float alpha) {
        int xl = x;
        int xh = x + w - 1;
        int yl = ih - 1 - (y + h - 1);
        int yh = ih - 1 - y;
        outputPacket(2, xl, xh, yl, yh);
        int rgb = c.toNonLinear().toRGB();
        int cr = (rgb >> 16) & 0xFF;
        int cg = (rgb >> 8) & 0xFF;
        int cb = rgb & 0xFF;
        byte[] rgba = new byte[4 * (yh - yl + 1) * (xh - xl + 1)];
        for (int j = 0, idx = 0; j < h; j++) {
            for (int i = 0; i < w; i++, idx += 4) {
                rgba[idx + 0] = (byte) (cr & 0xFF);
                rgba[idx + 1] = (byte) (cg & 0xFF);
                rgba[idx + 2] = (byte) (cb & 0xFF);
                rgba[idx + 3] = (byte) (0xFF);
            }
        }
        try {
            System.out.write(rgba);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized void imageEnd() {
        outputPacket(4, 0, 0, 0, 0);
        System.out.flush();
    }

    private void outputPacket(int type, int d0, int d1, int d2, int d3) {
        outputInt32(type);
        outputInt32(d0);
        outputInt32(d1);
        outputInt32(d2);
        outputInt32(d3);
    }

    private void outputInt32(int i) {
        System.out.write((i >> 24) & 0xFF);
        System.out.write((i >> 16) & 0xFF);
        System.out.write((i >> 8) & 0xFF);
        System.out.write(i & 0xFF);
    }
}