
package bricktest;

import com.tinkerforge.BrickletIndustrialDigitalIn4;
import com.tinkerforge.IPConnection;

/**
 *
 */
public class PotiTest implements BrickletIndustrialDigitalIn4.InterruptListener
{
    enum Direction {
        NONE,
        LEFT,
        RIGHT
    }

    private int currentIndex;
    private Direction direction;
    private boolean isDown;
    private boolean slow;
    private long ms;

    /**
     * Returns the following values:<br>
     * value == 0 -> return 0 = 0b00 <br>
     * value == 1 -> return 1 = 0b01 <br>
     * value == 2 -> return 3 = 0b11 <br>
     * value == 3 -> return 2 = 0b10
     * <P>
     * The values 0,1,3,2 define the value-sequence from the switch if it is
     * turned right slowly. If it is turned right fast, some values in between
     * are missing, so any of these values might arrive.
     * 
     * @param value current value
     * @return see description
     */
    static int getIndex(int value)
    {
        int v = value & 3;
        if (v == 2)
            return 3;
        if (v == 3)
            return 2;
        return v;
    }

    /**
     * Init with current value. In rare cases an interrupt is delivered at first connect.
     * This is why a "NONE" exists in the direction: ignore this value.
     * 
     * @param valueMask current value
     */
    public PotiTest(int valueMask)
    {
        currentIndex = getIndex(valueMask);
        direction = Direction.NONE;
        isDown = (valueMask & 4) != 0;
        ms = System.currentTimeMillis();
        slow = true;
    }

    /**
     * Callback
     */
    @Override
    public void interrupt(int interruptMask, int valueMask)
    {
        //System.out.println("Interrupt by: " + Integer.toBinaryString(interruptMask));
        //System.out.println("Value: " + Integer.toBinaryString(valueMask));
        
        if ((interruptMask & 4) != 0) {
            if ((valueMask & 4) != 0) {
                isDown = true;
                System.out.println("DOWN");
            }
            else {
                isDown = false;
                System.out.println("UP");
            }
            return;
        }

        long newMs = System.currentTimeMillis();
        int i = getIndex(valueMask);

        if (newMs - ms <= 150) {
            // fast movement: take old direction
            if (slow) {
                // If switch generates a second event immediately after a 'slow' move.
                // Skip this one, so that one raster move just counts as one.
                currentIndex = i;
                slow = false;
                ms = newMs;
                return;
            }
            System.out.print("fast ");
        }
        else if (i == currentIndex + 1) {
            direction = Direction.RIGHT;
            slow = true;
        }
        else if (i == currentIndex - 1) {
            direction = Direction.LEFT;
            slow = true;
        }
        else if (currentIndex == 3 && i == 0) {
            direction = Direction.RIGHT;
            slow = true;
        }
        else if (currentIndex == 0 && i == 3) {
            direction = Direction.LEFT;
            slow = true;
        }
        else {
            // Just for testing: if this really happens, the receive-thread dies!
            throw new RuntimeException("Logic error: i=" + i + ", currentIndex=" + currentIndex + "  time " + (newMs - ms));
        }

        currentIndex = i;
        ms = newMs;
        if (isDown) {
            System.out.print("DOWN ");
        }

        System.out.println(direction);
    }

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args)
        throws Exception
    {
        IPConnection ipcon = new IPConnection();
        
        // change UID, host and port for test...
        BrickletIndustrialDigitalIn4 di = new BrickletIndustrialDigitalIn4("coj", ipcon);
        ipcon.connect("tinkertest", 4223);
        
        // enable all 4 ports
        di.addInterruptListener(new PotiTest(di.getValue()));
        di.setInterrupt(8+4+2+1);
        
        System.out.println("Go for 30 seconds:");
        Thread.sleep(30 * 1000);
        System.out.println("Done!");
        ipcon.disconnect();
    }

}
