/*
 *****************************************************************************
 *                                                                           *
 *              IMPINJ CONFIDENTIAL AND PROPRIETARY                          *
 *                                                                           *
 * This source code is the sole property of Impinj, Inc. Reproduction or     *
 * utilization of this source code in whole or in part is forbidden without  *
 * the prior written consent of Impinj, Inc.                                 *
 *                                                                           *
 * (c) Copyright Impinj, Inc. 2014. All rights reserved.                     *
 *                                                                           *
 *****************************************************************************/

package com.impinj.stpexamples.inline;

import com.google.protobuf.TextFormat;
import com.impinj.stp.*;
import java.io.*;
import java.util.*;
import java.util.logging.*;

public class InlineSystem {
    InlineDevice inlineDevices[];
    TidTableEntryForwarder tidTableEntryForwarder;
    List<DebugStreamGrabber> debugStreamGrabbers;
    StpApi.Command.Builder[] configurations =
            new StpApi.Command.Builder[] {
                    StpApi.Command.newBuilder(),
                    StpApi.Command.newBuilder(),
                    StpApi.Command.newBuilder(),
                    StpApi.Command.newBuilder()};
    Properties prop;

    public InlineSystem() {
        prop = loadProperties("inline");

        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(InlineSystemFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(InlineSystemFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(InlineSystemFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            Logger.getLogger(InlineSystemFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        //</editor-fold>
        inlineDevices = new InlineDevice[] {
                new InlineDevice("First Verifier" , prop.getProperty("FirstVerifierIP")),
                new InlineDevice("First Encoder"  , prop.getProperty("FirstEncoderIP")),
                new InlineDevice("Second Encoder" , prop.getProperty("SecondEncoderIP")),
                new InlineDevice("Second Verifier", prop.getProperty("SecondVerifierIP"))
        };

        try {
            final SwingTableModelController modelController = new SwingTableModelController();
            debugStreamGrabbers = new ArrayList<DebugStreamGrabber>();
            TextFormat.merge(new FileReader("first_verifier.proto.txt"), configurations[0]);
            TextFormat.merge(new FileReader("first_encoder.proto.txt"),  configurations[1]);
            TextFormat.merge(new FileReader("second_encoder.proto.txt"), configurations[2]);
            TextFormat.merge(new FileReader("second_verifier.proto.txt"),configurations[3]);
            /* Create and display the form */
            java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new InlineSystemFrame(modelController, prop).setVisible(true);
            }
        });
        } catch (java.io.IOException ioe) {ioe.printStackTrace();}
    }
    public static void main(String[] args) {
        new InlineSystem();
    }
    // Swing UI Model Controller
    public class SwingTableModelController extends javax.swing.table.AbstractTableModel {
        final String rowNames[] = new String[] {"Pass Count", "Fail Count"};
        public SwingTableModelController() throws  IOException {
            super();
        }
        @Override
        public String getColumnName(int col) {
            if (0 == col){
                return "";
            } else {
                return inlineDevices[col - 1].getName();
            }
        }
        public Class getColumnClass(int col) {
            return getValueAt(0, col).getClass();
        }
        public int getRowCount() {
            return 2;
        }
        public int getColumnCount() {
            return 1 + inlineDevices.length;
        }
        public Object getValueAt(int row, int col) {
            if (0 == col) {
                return rowNames[row];
            } else {
                switch (row) {
                    case 0:
                        return inlineDevices[col - 1].getNumSuccess();
                    case 1:
                        return inlineDevices[col - 1].getNumFail();
                    default:
                        return -1;
                }
            }
        }
        @Override
        public boolean isCellEditable(int row, int col) {
            return false;
        }
        @Override
        public void setValueAt(Object value, int row, int col) {
            // pass
        }
        public void disengageDevices() throws Device.DeviceException {
            for (InlineDevice i: inlineDevices) {
                Device device = i.getDevice();
                device.stop();
                device.disengage();
            }
        }
        public void startDevices() throws Device.DeviceException {
            for (int i = 3; i >= 0; i--) {
                Device device = inlineDevices[i].getDevice();
                device.engage();
                if (inlineDevices[i].getName().endsWith("Encoder")){
                    try {
                        // this should become unnecessary with a future release
                        Thread.sleep(100);
                    } catch (InterruptedException ie) {
                        // do nothing
                    }
                    device.start();
                }
            }
        }
        public void connectDevices() throws  IOException, Device.DeviceException, Exception {
            // Send commands
            for (int i = 0; i < inlineDevices.length; i++) {
                inlineDevices[i].Connect();
                DebugStreamGrabber fddGrabber =
                        new DebugStreamGrabber(
                                inlineDevices[i].getAddress(),
                                DebugStreamGrabber.StreamType.FDD);
                fddGrabber.startPumperThread(inlineDevices[i]
                                .getName().replaceAll(" ", "_")
                                .trim().toLowerCase() + ".fdd");
                DebugStreamGrabber rddGrabber =
                        new DebugStreamGrabber(
                                inlineDevices[i].getAddress(),
                                DebugStreamGrabber.StreamType.RDD);
                rddGrabber.startPumperThread(inlineDevices[i]
                                .getName().replaceAll(" ", "_")
                                .trim().toLowerCase() + ".rdd");

                debugStreamGrabbers.add(fddGrabber);
                debugStreamGrabbers.add(rddGrabber);

                Device device = inlineDevices[i].getDevice();
                device.runSetDeviceConfigCommand(configurations[i].getSetDeviceConfigBuilder().build());
                device.runSetAntennaConfigCommand(configurations[i].getSetAntennaConfigBuilder().build());
                device.runAddSerializationJobCommand(configurations[i].getAddSerializationJobBuilder().build());
            }

            // Tid table
            TidTableSender tidTableSender = new TidTableSender();
            for (int i = 1; i < 4; i++) {
                tidTableSender.addTidTableListener(inlineDevices[i].getAddress());
            }
            long epc1to4 = Long.parseLong(prop.getProperty("Epc1to4"), 16);
            long epc5to8 = Long.parseLong(prop.getProperty("Epc5to8"), 16);
            tidTableEntryForwarder = new TidTableEntryForwarder(tidTableSender, (int)epc1to4, (int)epc5to8);
            tidTableEntryForwarder.HookUpToTagOperationReports(inlineDevices[0].getDevice());
        }
    }
    public static Properties loadProperties(String fileName) {
        Properties properties = new Properties();
        try {
            InputStream input;
            properties.load(input = new FileInputStream(fileName+".prop"));
            input.close();
        } catch(IOException e) {
            System.out.println(e);
        }
        return properties;
    }
}
