/**
 * Copyright (c) 2013-2014, TU Braunschweig
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of the University of California, Los Angeles nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package avrora.sim.util;

import avrora.sim.mcu.Microcontroller.Pin.Input;
import avrora.sim.mcu.Microcontroller.Pin.InputListener;
import avrora.sim.mcu.Microcontroller.Pin.Output;
import java.util.LinkedList;

/**
 *
 * @author S. Willenborg
 */
public class LCX138 {

    public final OPin A0 = new OPin("A0");
    public final OPin A1 = new OPin("A1");
    public final OPin A2 = new OPin("A2");

    public final OPin E1 = new OPin("E1");
    public final OPin E2 = new OPin("E2");
    public final OPin E3 = new OPin("E3");

    public final IPin O0 = new IPin("O0", 0);
    public final IPin O1 = new IPin("O1", 1);
    public final IPin O2 = new IPin("O2", 2);
    public final IPin O3 = new IPin("O3", 3);
    public final IPin O4 = new IPin("O4", 4);
    public final IPin O5 = new IPin("O5", 5);
    public final IPin O6 = new IPin("O6", 6);
    public final IPin O7 = new IPin("O7", 7);

    private int state = -1;

    public LCX138() {
        update();
    }

    private void update() {
        if (!E1.value && !E2.value && E3.value) {
            state = (A0.value ? 1 : 0) | (A1.value ? 2 : 0) | (A2.value ? 4 : 0);
        } else {
            state = -1;
        }
        O0.update();
        O1.update();
        O2.update();
        O3.update();
        O4.update();
        O5.update();
        O6.update();
        O7.update();

    }
    public class OPin implements Output {
        final String name;
        boolean value = false;

        public OPin(String name) {
            this.name = name;
        }

        @Override
        public void write(boolean level) {
            value = level;
            update();
        }
    }

    public class IPin implements Input {
        final String name;
        final int index;
        boolean cur_level = true;
        final LinkedList<InputListener> listeners = new LinkedList<>();

        public IPin(String name, int index) {
            this.name = name;
            this.index = index;
        }

        @Override
        public boolean read() {
            return cur_level;
        }

        private void update() {
             boolean new_level = (state != index);
             if (new_level != cur_level) {
                cur_level = new_level;
                for (InputListener listener : listeners) {
                    listener.onInputChanged(this, new_level);
                }
            }
        }

        @Override
        public void registerListener(InputListener listener) {
            if (!listeners.contains(listener)) {
                listeners.add(listener);
            }
        }

        @Override
        public void unregisterListener(InputListener listener) {
            if (listeners.contains(listener)) {
                listeners.remove(listener);
            }
        }

    }
}
