/*
 * Copyright (C) 2007  Lassi project
 *
 * This file is part of Lassi; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Lassi is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Lassi; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * http://www.lassi.be
 */

package help.pages.tutorials.java;

import java.awt.Color;

import be.lassi.domain.Colors;
import be.lassi.domain.Fixture;
import be.lassi.domain.FixtureDefinition;
import be.lassi.domain.FixtureGroups;
import be.lassi.domain.Fixtures;
import be.lassi.domain.NamedColor;
import be.lassi.lanbox.domain.MixMode;
import be.lassi.lanbox.domain.Time;
import be.lassi.lanbox.tools.CueListBuilder;

/**
 * Builds cuelists for the lighting effects for the production
 * of "Simon Vedelaar" (May 2009): chases on 9 LED bars (with
 * three segments each, mounted in a fan-like shape.
 */
public class Simon extends CueListBuilder {

    private static final int START_ADDRESS = 70;

    private static final int BAR_COUNT = 9;
    private static final int SEGMENTS_PER_BAR = 3;

    private final Fixtures conventionals = new Fixtures();
    private final Fixtures segments = new Fixtures();
    private final Fixtures strobes = new Fixtures();
    private final Fixtures dimmers = new Fixtures();

    private final FixtureGroups bars = new FixtureGroups(BAR_COUNT);
    private final FixtureGroups circles = new FixtureGroups(SEGMENTS_PER_BAR);

    public static void main(final String[] args) {
        new Simon().buildCueLists();
    }

    public void buildCueLists() {
        buildFixtures();
        setupLayers();
        baseLine();
        dimmersOn();
        dimmersOff();
        stop();
        wiper1();
        wiper2();
        threeCircleWiper();
        cycleColors(1, 500, 1000);
        cycleColors(2, 2000, 4000);
        wheel();
        random("RED");
        random("GREEN");
        random("BLUE");
        random("YELLOW");
        random("CYAN");
        random("MAGENTA");
        radiator();
        rainbow("SLOW", 500);
        rainbow("FAST", 50);

        writeCueLists();
    }

    private void buildFixtures() {
        int address = 1;
        for (int i=0; i < START_ADDRESS - 1; i++) {
            conventionals.add(dimmer(address++));
        }
        for (Fixtures bar : bars) {
            for (Fixtures circle : circles) {
                Fixture segment = rgb(address);
                segments.add(segment);
                circle.add(segment);
                bar.add(segment);
                address += 3;
            }
            strobes.add(dimmer(address++));
            dimmers.add(dimmer(address++));
        }
    }

    private void setupLayers() {
        createCueList("SETUP");

        resetLayer(LAYER_A);
        resetLayer(LAYER_B);
        resetLayer(LAYER_C);
        resetLayer(LAYER_D);

        setLayerMixMode(LAYER_A, MixMode.HTP);
        setLayerMixMode(LAYER_B, MixMode.HTP);
        setLayerMixMode(LAYER_C, MixMode.HTP);
        setLayerMixMode(LAYER_D, MixMode.COPY);
    }

    private void baseLine() {
        createCueList("BASELINE");
        setIntensity(conventionals, 0);
        setIntensity(dimmers, 0);
        setIntensity(strobes, 0);
        setColor(segments, Color.BLACK);
        crossFade(seconds(2), Time.FOREVER);
    }

    private void dimmersOn() {
        createCueList("DIMMERS\nON");
        setIntensity(dimmers, 100);
        crossFade(seconds(2), Time.FOREVER);
    }

    private void dimmersOff() {
        createCueList("DIMMERS\nOFF");
        setIntensity(dimmers, 0);
        crossFade(seconds(2), Time.FOREVER);
    }

    private void stop() {
        createCueList("STOP");
        resetLayer(LAYER_A);
    }

    private void wiper1() {
        createCueList("WIPER1");
        Time holdTime = millis(50);
        Colors colors = new Colors("red", "green", "blue", "yellow");
        for (Color color : colors) {
            for (Fixtures bar : bars) {
                setColor(bar, color);
                hold(holdTime);
            }
            for (Fixtures bar : bars.reversed()) {
                setColor(bar, color);
                hold(holdTime);
            }
        }
        loopTo(1, 10);
    }

    private void wiper2() {
        createCueList("WIPER2");
        Time time = millis(150);
        Colors colors = new Colors();
        Color color = colors.next();
        Colors barColors = new Colors(color, bars.size());
        for (int i=0; i < 4; i++) {
            color = colors.next();
            for (int j=0; j < bars.size(); j++) {
                barColors.set(j, color);
                setColors(bars, barColors);
                hold(time);
            }
            color = colors.next();
            for (int j=bars.size() - 1; j > 0; j--) {
                barColors.set(j, color);
                setColors(bars, barColors);
                hold(time);
            }
        }
        loopTo(1, 10);
    }

    private void threeCircleWiper() {
        createCueList("3 CIRCLE\nWIPER");

        Fixtures fixtures = new Fixtures();
        fixtures.addAll(circles.get(0));
        fixtures.addAll(circles.get(1).reversed());
        fixtures.addAll(circles.get(2));

        Colors colors = new Colors("green", "blue", "red");
        Colors fixtureColors = new Colors(colors.last(), fixtures.size());
        for (Color color : colors) {
            for (int i=0; i < fixtures.size(); i++) {
                fixtureColors.set(i, color);
                setColors(fixtures, fixtureColors);
                hold(millis(50));
            }
        }
        loopTo(1, 10);
    }

    private void cycleColors(final int id, final int fadeMillis, final int holdMillis) {
        createCueList("CYCLE\nCOLORS " + id);
        Time fadeTime = millis(fadeMillis);
        Time holdTime = millis(holdMillis);
        Colors colors = new Colors();
        for (Color color : colors) {
            setColor(segments, color);
            crossFade(fadeTime, holdTime);
        }
        loopTo(1, 10);
    }

    private void wheel() {
        createCueList("WHEEL");
        FixtureGroups spokeGroups = buildSpokeGroups();
        int cueStepNumber = nextCueStepNumber();
        for (Color color : new Colors()) {
            for (Fixtures spokeGroup : spokeGroups) {
                setColor(spokeGroup, color);
                hold(millis(100));
            }
            loopTo(cueStepNumber, 10);
            cueStepNumber = nextCueStepNumber();
        }
        loopTo(1, 10);
    }

    private FixtureGroups buildSpokeGroups() {
        Fixtures spokeGroup1 = new Fixtures();
        spokeGroup1.addAll(bars.get(0));
        spokeGroup1.addAll(bars.get(3));
        spokeGroup1.addAll(bars.get(6));

        Fixtures spokeGroup2 = new Fixtures();
        spokeGroup2.addAll(bars.get(1));
        spokeGroup2.addAll(bars.get(4));
        spokeGroup2.addAll(bars.get(7));

        Fixtures spokeGroup3 = new Fixtures();
        spokeGroup3.addAll(bars.get(2));
        spokeGroup3.addAll(bars.get(5));
        spokeGroup3.addAll(bars.get(8));

        FixtureGroups spokeGroups = new FixtureGroups();

        spokeGroups.add(spokeGroup1);
        spokeGroups.add(spokeGroup2);
        spokeGroups.add(spokeGroup3);

        return spokeGroups;
    }

    private void random(final String colorName) {
        createCueList("RANDOM\n" + colorName);
        Color color = NamedColor.getColor(colorName);
        for (Fixture segment : segments.shuffled()) {
            setColor(segment, color);
            hold(millis(50));
        }
        loopTo(1, 10);
    }

    private void radiator() {
        createCueList("RADIATOR");
        for (Color color : new Colors()) {
            for (Fixtures circle : circles) {
                setColor(circle, color);
                hold(millis(250));
            }
        }
        loopTo(1, 10);
    }

    private void rainbow(final String name, final int time) {
        createCueList(name + "\nRAINBOW");
        Time fadeTime = millis(time);
        Time holdTime = fadeTime;

        int steps = 30;
        float start = 0.0f;
        float delta = 1.0f / steps;

        for (int i=0 ; i < steps; i++) {
            for (int j=0 ; j < bars.size(); j++) {
                float hue = start + (j * 0.1f);
                if (hue > 1f) {
                    hue -= 1f;
                }
                Color color = colorWithHue(hue);
                setColor(bars.get(j), color);
            }
            crossFade(fadeTime, holdTime, true);
            start += delta;
            if (start > 1.0f) {
                start = start - 1f;
            }
        }
        loopTo(1, 100);
    }

    private Fixture rgb(final int address) {
        FixtureDefinition definition = new FixtureDefinition();
        definition.addAttribute("Red", "1");
        definition.addAttribute("Green", "2");
        definition.addAttribute("Blue", "3");
        return new Fixture(definition, "", address);
    }

    private Fixture dimmer(final int address) {
        FixtureDefinition definition = new FixtureDefinition();
        definition.addAttribute("Intensity", "1");
        return new Fixture(definition, "", address);
    }
}

