package com.stario;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;

import com.starmicronics.stario.PortInfo;
import com.starmicronics.stario.StarIOPort;
import com.starmicronics.stario.StarIOPortException;
import com.starmicronics.stario.StarPrinterStatus;


public class PrinterFunctions
{
	public enum Alignment {
		Left, Center, Right
	};
	
    /**
     * This function checks the status of the printer
     * @param context - Activity for displaying messages to the user
     * @param portName - Port name to use for communication. This should be (TCP:<IPAddress>)
     * @param portSettings - Should be blank
     * @param sensorActiveHigh - boolean variable to tell the sensor active of CashDrawer which is High
     */
    public static StarPrinterStatus GetStatus(String portName, String portSettings, boolean sensorActiveHigh) throws StarIOPortException {
        StarIOPort port = null;
        StarPrinterStatus status = null;
        try {
            port = StarIOPort.getPort(portName, portSettings, 10000);

            try {
                Thread.sleep(500);
            }
            catch(InterruptedException e) {}

            status = port.retreiveStatus();
        }
        catch (StarIOPortException e) {
            // Bubbling the exception up
            throw e;
        }
        finally {
            if(port != null) {
                try {
                    StarIOPort.releasePort(port);
                } catch (StarIOPortException e) {}
            }
        }
        return status;
    }

    /**
     * Using the portNameSearch parameter, this method searches for the first printer that corresponds to the
     * search
     * @param portNameSearch the name of the printer to search (example BT: or TCP:xxx.xxx.xxx.xxx)
     * @return
     */
    public static String getFirstPrinter(String portNameSearch) {
        String portName = "";
        List<PortInfo> portList;
        try {
            portList  = StarIOPort.searchPrinter(portNameSearch);

            for (PortInfo portInfo : portList) {
                portName = portInfo.getPortName();
                break;
            }
        } catch (StarIOPortException e) {
            e.printStackTrace();
        }
        return portName;
    }

    private static byte[] convertFromListByteArrayTobyteArray2(List<Byte> ByteArray) {
        byte[] byteArray = new byte[ByteArray.size()];
        for(int index = 0; index < byteArray.length; index++) {
            byteArray[index] = ByteArray.get(index);
        }

        return byteArray;
    }

    public static void CopyArray(byte[] srcArray, Byte[] cpyArray) {
        for (int index = 0; index < cpyArray.length; index++) {
            cpyArray[index] = srcArray[index];
        }
    }
    
    private static byte[] convertFromListByteArrayTobyteArray(List<byte[]> ByteArray) {
		int dataLength = 0;
		for (int i = 0; i < ByteArray.size(); i++) {
			dataLength += ByteArray.get(i).length;
		}

		int distPosition = 0;
		byte[] byteArray = new byte[dataLength];
		for (int i = 0; i < ByteArray.size(); i++) {
			System.arraycopy(ByteArray.get(i), 0, byteArray, distPosition, ByteArray.get(i).length);
			distPosition += ByteArray.get(i).length;
		}

		return byteArray;
	}
	
    public static boolean sendCommand(String portName, String portSettings, ArrayList<byte[]> byteList) {
		boolean result = true;
		StarIOPort port = null;
		try {

			port = StarIOPort.getPort(portName, portSettings, 50000);

			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
			}

			StarPrinterStatus status = port.retreiveStatus();

			if (true == status.offline) {
				throw new StarIOPortException("A printer is offline");
			}

			byte[] commandToSendToPrinter = convertFromListByteArrayTobyteArray(byteList);
			port.writePort(commandToSendToPrinter, 0, commandToSendToPrinter.length);


			if (true == status.coverOpen) {
				throw new StarIOPortException("Printer cover is open");
			} else if (true == status.receiptPaperEmpty) {
				throw new StarIOPortException("Receipt paper is empty");
			} else if (true == status.offline) {
				throw new StarIOPortException("Printer is offline");
			}

		} catch (StarIOPortException e) {
			
			System.err.println("Privy 2: " + e.getMessage());
			result = false;
			
		} finally {
			if (port != null) {
				try {
					StarIOPort.releasePort(port);
				} catch (StarIOPortException e) {
				}
			}
		}
		
		return result;
	}
	
    public static void SendCommand2(String portName, String portSettings, ArrayList<Byte> byteList) throws StarIOPortException {
        StarIOPort port = null;
        try {
            /*
                using StarIOPort3.1.jar (support USB Port)
                Android OS Version: upper 2.2
            */
            port = StarIOPort.getPort(portName, portSettings, 10000);
            /*
                using StarIOPort.jar
                Android OS Version: under 2.1
                port = StarIOPort.getPort(portName, portSettings, 10000);
            */
            try {
                Thread.sleep(100);
            }
            catch (InterruptedException e) { 
	            e.printStackTrace();
            }

			StarPrinterStatus status = port.retreiveStatus();
			
            if (status.offline) {
                throw new StarIOPortException("A printer is offline");
            }

            byte[] commandToSendToPrinter = convertFromListByteArrayTobyteArray2(byteList);
            port.writePort(commandToSendToPrinter, 0, commandToSendToPrinter.length);
			
            if (status.coverOpen) {
                throw new StarIOPortException("Printer cover is open");
            }
            else if (status.receiptPaperEmpty) {
                throw new StarIOPortException("Receipt paper is empty");
            }
            else if (status.offline) {
                throw new StarIOPortException("Printer is offline");
            }
        } finally {
			if (port != null) {
				try {
					StarIOPort.releasePort(port);
				} catch (StarIOPortException e) {
				}
			}
		}
    }
    
    public static ArrayList<byte[]> FormatText(String portName, String portSettings, boolean underline, boolean emphasized, boolean upsidedown, boolean invertColor, byte heightExpansion, byte widthExpansion, int leftMargin, PrinterFunctions.Alignment alignment, byte[] textToPrint) {
		
		ArrayList<byte[]> commands = new ArrayList<byte[]>();

		commands.add(new byte[] { 0x1b, 0x40 }); // Initialization

		byte[] underlineCommand = new byte[] { 0x1b, 0x2d, 0x00 };
		if (underline) {
			underlineCommand[2] = 49;
		} else {
			underlineCommand[2] = 48;
		}
		commands.add(underlineCommand);

		byte[] emphasizedCommand = new byte[] { 0x1b, 0x45, 0x00 };
		if (emphasized) {
			emphasizedCommand[2] = 1;
		} else {
			emphasizedCommand[2] = 0;
		}
		commands.add(emphasizedCommand);

		byte[] upsidedownCommand = new byte[] { 0x1b, 0x7b, 0x00 };
		if (upsidedown) {
			upsidedownCommand[2] = 1;
		} else {
			upsidedownCommand[2] = 0;
		}
		commands.add(upsidedownCommand);

		byte[] invertColorCommand = new byte[] { 0x1d, 0x42, 0x00 };
		if (invertColor) {
			invertColorCommand[2] = 1;
		} else {
			invertColorCommand[2] = 0;
		}
		commands.add(invertColorCommand);

		byte[] characterSizeCommand = new byte[] { 0x1d, 0x21, 0x00 };
		characterSizeCommand[2] = (byte) (heightExpansion | (widthExpansion << 4));
		commands.add(characterSizeCommand);

		byte[] leftMarginCommand = new byte[] { 0x1d, 0x4c, 0x00, 0x00 };
		leftMarginCommand[2] = (byte) (leftMargin % 256);
		leftMarginCommand[3] = (byte) (leftMargin / 256);
		commands.add(leftMarginCommand);

		byte[] justificationCommand = new byte[] { 0x1b, 0x61, 0x00 };
		switch (alignment) {
		case Left:
			justificationCommand[2] = 48;
			break;
		case Center:
			justificationCommand[2] = 49;
			break;
		case Right:
			justificationCommand[2] = 50;
			break;
		}
		commands.add(justificationCommand);

		commands.add(textToPrint);

		commands.add(new byte[] {0x0a});

		return commands;
	}
	
	protected static byte[] ReplaceCommand(byte[] tempDataBytes) {

		byte[] buffer = new byte[tempDataBytes.length];
		int j = 0;
		
		byte[] specifyJISkanjiCharacterModeCommand = new byte[] {0x1b, 0x70};
		byte[] cancelJISkanjiCharacterModeCommand = new byte[] {0x1b, 0x71};
		
		//replace command
		//Because LF(0x0A) command is not performed.
		if(tempDataBytes.length > 0){
			for(int i=0; i<tempDataBytes.length; i++){
				if(tempDataBytes[i] == 0x1b){
					if(tempDataBytes[i+1] == 0x24){// Replace [0x1b 0x24 0x42] to "Specify JIS Kanji Character Mode" command
						buffer[j]   = specifyJISkanjiCharacterModeCommand[0];
						buffer[j+1] = specifyJISkanjiCharacterModeCommand[1];
						j += 2;
					}
					else if(tempDataBytes[i+1] == 0x28){//Replace [0x1b 0x28 0x42] to "Cancel JIS Kanji Character Mode" command
						buffer[j]   = cancelJISkanjiCharacterModeCommand[0];
						buffer[j+1] = cancelJISkanjiCharacterModeCommand[1];
						j += 2;
					}
					
					i += 2;
				}else{
					buffer[j] = tempDataBytes[i];
					j++;
				}
			}
		}
		
		//check 0x00 position
		int datalength = 0;
		for(int i=0; i< buffer.length; i++){
			if(buffer[i] == 0x00){
				datalength = i;
				break;
			}
		}
		
		//copy data
		if(datalength == 0){
			datalength = buffer.length;
		}
		byte[] data = new byte[datalength];		
		System.arraycopy(buffer, 0, data, 0, datalength);

		return data;
	}
}
