package com.nanotec.example.nanolibexample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.nanotec.example.nanolibexample.NanolibHelper.NanolibException;
import com.nanotec.nanolib.BusHWIdVector;
import com.nanotec.nanolib.BusHardwareId;
import com.nanotec.nanolib.BusHardwareOptions;
import com.nanotec.nanolib.DeviceHandle;
import com.nanotec.nanolib.DeviceId;
import com.nanotec.nanolib.DeviceIdVector;
import com.nanotec.nanolib.IntVector;
import com.nanotec.nanolib.LogLevel;
import com.nanotec.nanolib.OdIndex;
import com.nanotec.nanolib.ProfinetDCP;
import com.nanotec.nanolib.Nanolib;

/**
 * Nanolib Example
 */
public class NanolibExample {
	private static NanolibHelper nanolibHelper = new NanolibHelper();

	public static void main(String[] args) {
		try {
			nanolibHelper.setup();

			// list all hardware available, decide for the first one
			BusHWIdVector busHwIds = nanolibHelper.getBusHardware();

			// its possible to set the logging level to a different level
			nanolibHelper.setLoggingLevel(LogLevel.Off);

			if (busHwIds.isEmpty()) {
				System.out.println("No bus hardware found");
				return;
			}

			System.out.println();
			System.out.println("Available bus hardware:");
			System.out.println();

			int lineNum = 0;

			// just for better overview: print out available hardware
			for (BusHardwareId adapter : busHwIds) {
				System.out.print(String.format("%d. %s", lineNum, adapter.getName()));
				System.out.println(String.format(" with protocol: %s", adapter.getProtocol()));
				lineNum++;
			}

			System.out.println();
			System.out.print("Please select (enter) bus hardware number(0-" + (lineNum - 1) + ") and press [ENTER]:");

			// Enter data using BufferReader
			BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

			lineNum = -1;

			try {
				lineNum = Integer.parseInt(reader.readLine());
			} catch (NumberFormatException e) {
			}

			System.out.println();

			if (lineNum < 0 || lineNum >= busHwIds.size()) {
				System.out.println("Invalid selection!");
				return;
			}

			BusHardwareId busHwId = busHwIds.get(lineNum);

			// create bus hardware options for opening the hardware
			BusHardwareOptions busHwOptions = nanolibHelper.createBusHardwareOptions(busHwId);

			// now able to open the hardware itself
			nanolibHelper.openBusHardware(busHwId, busHwOptions);

			//nanolibHelper.setLoggingLevel(LogLevel.Off);

			System.out.println("Scanning for devices...");

			// either scan the whole bus for devices (in case the bus supports scanning)
			DeviceIdVector deviceIds = nanolibHelper.scanBus(busHwId);

			//nanolibHelper.setLoggingLevel(LogLevel.Off);

			System.out.println("");
			for (DeviceId id : deviceIds) {
				System.out.println(String.format("Found device: %d", id.getDeviceId()));
			}

			if (deviceIds.isEmpty()) {
				nanolibHelper.closeBusHardware(busHwId);
				System.out.println("No devices found.");
				return;
			}

			System.out.println();
			System.out.println("Available devices:");
			System.out.println();

			lineNum = 0;

			// just for better overview: print out available hardware
			for (DeviceId id : deviceIds) {
				System.out.print(String.format("%d. %s", lineNum, id.getDescription()));
				System.out.println(String.format("[device id: %d, hardware: %s]", id.getDeviceId(),
						id.getBusHardwareId().getName()));
				lineNum++;
			}

			System.out.println();
			System.out.print("Please select (enter) device number(0-" + (lineNum - 1) + ") and press [ENTER]:");

			lineNum = -1;

			try {
				lineNum = Integer.parseInt(reader.readLine());
			} catch (NumberFormatException e) {
			}

			System.out.println();

			if (lineNum < 0 || lineNum >= deviceIds.size()) {
				System.out.println("Invalid selection!");
				return;
			}

			// We can create the device id manually
			// Nlc.DeviceId deviceId = new Nlc.DeviceId(busHwId, 1, "");
			// or get seletced device
			DeviceId deviceId = new DeviceId(deviceIds.get(lineNum)); // Very important step in the C# version of
																	// Nanolib
			// Create a copy of every object, which is returned in container, because
			// when container goes out of scope, the contained objects will be destroyed.

			// Create a device and get a handle
			DeviceHandle deviceHandle = nanolibHelper.createDevice(deviceId);

			// now connect to the device
			nanolibHelper.connectDevice(deviceHandle);

			// now ready to work with the device, here are some examples on how to access
			// the
			// object dictionary:
			objectDictionaryAccessExamples(nanolibHelper, deviceHandle);

			if(busHwId.getBusHardware() == Nanolib.getBUS_HARDWARE_ID_NETWORK()) {

				ProfinetDCP profinetDcpInterface = nanolibHelper.getProfinetDcpInterface();
				if(!profinetDcpInterface.isServiceAvailable(busHwId).hasError()) 
				{
            		if(askUser("Do you wish to proceed with Profinet DCP example? Press 'Y'es / 'N'o: ", reader)) 
					{
                		NanolibProfinetExample profinetExample = new NanolibProfinetExample();
						profinetExample.setup(busHwId, profinetDcpInterface);
                		profinetExample.execute();
					}
				}
			}

			if(askUser("Do you wish to proceed with sampler examples? Press 'Y'es / 'N'o: ", reader)) {

				NanolibSamplerExample samplerExample = new NanolibSamplerExample(nanolibHelper, deviceHandle);
				samplerExample.process();
			}

			// cleanup and close everything
			nanolibHelper.disconnectDevice(deviceHandle);
			nanolibHelper.closeBusHardware(busHwId);

			System.out.println("Closing everything successfully");
			System.out.println("");

		} catch (Exception e) {
			System.out.println(String.format("Error occured: %s", e.getMessage()));
		}
	}

	private static Boolean askUser(String text, BufferedReader reader) throws IOException {
		
		System.out.println(text);
		try {
			int input = reader.read();
			
			return (input == 121 || input == 89);
		} catch (NumberFormatException e) {
		}

		return false;
	}

	private static void objectDictionaryAccessExamples(NanolibHelper nanolibHelper, DeviceHandle deviceId)
			throws NanolibException {
		// OD example
		System.out.println("");
		System.out.println("OD Example");
		System.out.println("");

		// read status word
		System.out.println("Reading subindex 0 of index 0x6040");
		long statusWord = nanolibHelper.readNumber(deviceId, new OdIndex(0x6040, (short) 0x00));
		System.out.println(String.format("Result: 0x%04X", statusWord));
		System.out.println("");

		// write control word to value "6"
		System.out.println("Motor Stop (0x6040-0)");
		System.out.println("");
		nanolibHelper.writeNumber(deviceId, 6, new OdIndex(0x6040, (short) 0x00), 16);

		// read homepage of nanotec
		System.out.println("Read Nanotec home page string");
		System.out.println(String.format("The home page of Nanotec Electronic GmbH & Co. KG is: %s",
				nanolibHelper.readString(deviceId, new OdIndex(0x6505, (short) 0x00))));
		System.out.println("");

		// read error stack
		System.out.println("Read device error stack");
		IntVector errorStack = nanolibHelper.readArray(deviceId, 0x1003);
		System.out.println(String.format("The error stack has %d elements", errorStack.get(0)));
		System.out.println("");
	}
}
