package utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.UUID;
import java.util.Vector;

import com.printer.bluetooth.android.BluetoothPrinter;
import com.printer.bluetooth.android.FontProperty;
import com.printer.bluetooth.android.PrintGraphics;
import com.printer.bluetooth.android.PrinterType;

import android.app.ProgressDialog;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass.Device;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
import com.esl.lib.PaypadFacade;
import org.json.JSONException;
import org.json.JSONObject;
import org.apache.cordova.*;
import extras.ReferenceList;
import android.content.SharedPreferences;
import models.messaging.nibss.Globals;


public class BluetoothService extends Service {

	private BluetoothAdapter mBluetoothAdapter;
	public static final String BT_DEVICE = "btdevice";
	public static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
	public static final int STATE_NONE = 0; // we're doing nothing
	public static final int STATE_LISTEN = 1; // now listening for incoming
												// connections
	public static final int STATE_CONNECTING = 2; // now initiating an outgoing
													// connection
	public static final int STATE_CONNECTED = 3; // now connected to a remote
	
	private static Handler mHandler = null, pHandler = null;
	public static int mState = STATE_NONE;
	public static String deviceName;
	public Vector<Byte> packdata = new Vector<Byte>(2048);
	public static Device device = null;
    private static BluetoothPrinter bluetoothPrinter;

    private ProgressDialog mConnectingDlg;
	
	// Key names received from the BluetoothChatService Handler
	public static final String DEVICE_NAME = "device_name";
	public static final String TOAST = "toast";
	
	private static final String NAME_SECURE = "BluetoothChatSecure";

	String macAddress = null;

	@Override
	public void onCreate() {
		Log.d("BluetoothService", "Service started");
		super.onCreate();
//		printerUtility = PrinterUtility.getInstance(getApplicationContext());
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d("BluetoothService", "Onstart Command");
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		if (mBluetoothAdapter != null) {
//			device = (Device) intent.getSerializableExtra(BT_DEVICE);
//			deviceName = device.getDeviceName();
//			String macAddress = device.getMacAddress();
			try{
				macAddress = intent.getExtras().getString(PaypadFacade.DEVICE_ADDRESS);

	            BluetoothDevice bluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);

				if (macAddress != null && macAddress.length() > 0) {
					connectToDevice(bluetoothDevice);
				} else {
					stopSelf();
					return 0;
				}
			}catch(Exception ex){

			}	
		}
//		String stopservice = intent.getStringExtra("stopservice");
//		if (stopservice != null && stopservice.length() > 0) {
//			stop();
//		}
		return START_STICKY;
	}

    public class LocalBinder extends Binder {
        public BluetoothService getService() {
            return BluetoothService.this;
        }
    }

	private synchronized void connectToDevice(BluetoothDevice device) {

        try {
            initPrinter(device);
        }catch(Exception ex){
            ex.printStackTrace();
        }

		setState(STATE_CONNECTING);
	}

	 public static boolean closePinter(){

        try{

            if(bluetoothPrinter != null) {
                bluetoothPrinter.closeConnection();
                bluetoothPrinter = null;
            }

            return true;

        }catch(Exception ex){

        }

        return false;
    }

	public static boolean isPrinterConnected(){

        if(bluetoothPrinter == null){
            return false;
        }

        if(!bluetoothPrinter.isConnected()){
            return false;
        }

        return true;
    }

    private void initPrinter(BluetoothDevice bluetoothDevice){
        if(!isPrinterConnected()){
        	bluetoothPrinter = new BluetoothPrinter(bluetoothDevice);

	        bluetoothPrinter.setCurrentPrintType(PrinterType.TIII);

	        if(pHandler == null){
	            pHandler = new Handler() {
	                @Override
	                public void handleMessage(Message msg) {
	//                    Log.i(TAG, "msg.what is : " + msg.what);
	                    switch (msg.what) {
	                        case BluetoothPrinter.Handler_Connect_Connecting:
	                            System.out.println("Printer connecting");
	//                            isConnecting = true;
	//                            mTitle.setText(R.string.title_connecting);
	                            //Toast.makeText(getApplicationContext(), R.string.bt_connecting,Toast.LENGTH_SHORT).show();
	                            break;
	                        case BluetoothPrinter.Handler_Connect_Success:
	                            System.out.println("Printer connection successful");

	                            try {
	                                JSONObject jsonObject = new JSONObject();
	                                jsonObject.put("operation", "connectprinter");
	                                jsonObject.put("status","connected");

	                                PluginResult result = new PluginResult(PluginResult.Status.OK, jsonObject);
									result.setKeepCallback(false);
									PaypadFacade.callbackContext.sendPluginResult(result);

	                            }catch(JSONException ex){
	                                
	                            }

	                            SharedPreferences.Editor editor = ReferenceList.config.edit();
	                            editor.putString(Globals.printerAddressKey,macAddress);
	                            editor.commit();

	//                            isConnected = true;
	//                            isConnecting = false;
	//                            mTitle.setText(getString(R.string.title_connected) + ": "+ mPrinter.getPrinterName());
	                            //Toast.makeText(getApplicationContext(), R.string.bt_connect_success,Toast.LENGTH_SHORT).show();
	                            break;
	                        case BluetoothPrinter.Handler_Connect_Failed:
	                            System.out.println("Printer connection failed");

	                            // This mostly happens when the device is not available
	                            try {
	                                JSONObject jsonObject = new JSONObject();
	                                jsonObject.put("operation", "connectprinter");
	                                jsonObject.put("status","failed");

	                                PluginResult result = new PluginResult(PluginResult.Status.OK, jsonObject);
									result.setKeepCallback(false);
									PaypadFacade.callbackContext.sendPluginResult(result);

	                            }catch(JSONException ex){
	                                
	                            }

	//                            isConnected = false;
	//                            isConnecting = false;
	//                            mTitle.setText(R.string.title_not_connected);
	                            //Toast.makeText(getApplicationContext(), R.string.bt_connect_failed, Toast.LENGTH_SHORT).show();
	                            break;
	                        case BluetoothPrinter.Handler_Connect_Closed:

	                            System.out.println("Printer is closing");
	//                            isConnected = false;
	//                            isConnecting = false;
	//                            mTitle.setText(R.string.title_not_connected);
	                            //Toast.makeText(getApplicationContext(), R.string.bt_connect_closed, Toast.LENGTH_SHORT).show();
	                            break;
	                    }
	//                    setButtonState();
	                }
	            };
	        }

	        bluetoothPrinter.setHandler(pHandler);
	        bluetoothPrinter.openConnection();
	        bluetoothPrinter.setEncoding("UTF-8");
	    }
    }

	private void setState(int state) {

		BluetoothService.mState = state;
//		if (mHandler != null) {
//			mHandler.obtainMessage(BaseActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
//		}
	}
	
	/**
	 * Return the current connection state.
	 */
	public synchronized int getState() {
		return mState;
	}

	
//	private synchronized void connected(BluetoothSocket mmSocket,
//			BluetoothDevice mmDevice) {
//
//		 Message msg = mHandler.obtainMessage(BaseActivity.MESSAGE_DEVICE_NAME);
//		 Bundle bundle = new Bundle();
//		 bundle.putString(DEVICE_NAME, mmDevice.getName());
//		 msg.setData(bundle);
//		 mHandler.sendMessage(msg);
//
//		mConnectedThread = new ConnectedThread(mmSocket);
//		mConnectedThread.start();
//
//		setState(STATE_CONNECTED);
//
//	}
//
	public synchronized void stop() {
		setState(STATE_NONE);

		if (mBluetoothAdapter != null) {
			mBluetoothAdapter.cancelDiscovery();
		}

        if(bluetoothPrinter != null){
            bluetoothPrinter.closeConnection();
        }

		stopSelf();
	}

	@Override
	public boolean stopService(Intent name) {
		setState(STATE_NONE);

		mBluetoothAdapter.cancelDiscovery();
		return super.stopService(name);
	}

	private static Object obj = new Object();


    public void print(PrintModel sb) {
        // Create temporary object
//        ConnectedThread r;

        if(printReceipt(sb,true)){
//            printReceipt(sb,false);
        }

//        printerUtility.printMessage(sb);
    }

    private boolean printReceipt(PrintModel sb, boolean customer){

        // This is called every thing a receipt it to be printed
        bluetoothPrinter.init();

//        PrintGraphics printGraphics = new PrintGraphics();

        int x = 0, y = 0;
//        printGraphics.init(bluetoothPrinter.getCurrentPrintType());
//
//        FontProperty FONT_48PX = new FontProperty();
//        FONT_48PX.setFont(true,false,false,false,24, Typeface.SANS_SERIF);

//        byte[] header = com.printer.Printer.printfont(sb.getHeader() + "",
//                FontDefine.FONT_48PX, FontDefine.Align_CENTER, (byte) 0x1A, PocketPos.LANGUAGE_ENGLISH);

        bluetoothPrinter.setPrinter(BluetoothPrinter.COMM_ALIGN, BluetoothPrinter.COMM_ALIGN_CENTER);
        bluetoothPrinter.setCharacterMultiple(1,1);

        bluetoothPrinter.printText(sb.getHeader() + "\n");

        StringBuffer subHeaderBuffer = new StringBuffer();

        for(String s : sb.getSubHeader()){
            subHeaderBuffer.append(s+"\n");
        }

        bluetoothPrinter.setCharacterMultiple(0,0);

        if(customer == true) {
            subHeaderBuffer.append("Customer's Copy \n");
        }else{
            subHeaderBuffer.append("Merchant's Copy \n");
        }

//        byte[] subHeader = com.printer.Printer.printfont(subHeaderBuffer.toString() + "\n",
//                FontDefine.FONT_32PX, FontDefine.Align_CENTER, (byte) 0x1A, PocketPos.LANGUAGE_ENGLISH);

        bluetoothPrinter.printText(subHeaderBuffer.toString()+"\n");

        Map<String, String> message = sb.getBody();

        StringBuffer bodyBuffer = new StringBuffer();

        if (message != null) {
            if (!message.isEmpty()) {
                for (String s : message.keySet()) {
                    bodyBuffer.append(format(s, 15) + " : " + message.get(s)+"\n");
                }
            }
        }
        bodyBuffer.append("\n");

        bluetoothPrinter.setPrinter(BluetoothPrinter.COMM_ALIGN, BluetoothPrinter.COMM_ALIGN_LEFT);
        bluetoothPrinter.setCharacterMultiple(0,0);

        bluetoothPrinter.printText(bodyBuffer.toString());



//        byte[] body = com.printer.Printer.printfont(bodyBuffer.toString() + "\n",
//                FontDefine.FONT_24PX, FontDefine.Align_LEFT, (byte) 0x1A, PocketPos.LANGUAGE_ENGLISH);

//        byte[] footer = com.printer.Printer.printfont(sb.getFooter() + "\n",
//                FontDefine.FONT_32PX, FontDefine.Align_CENTER, (byte) 0x1A, PocketPos.LANGUAGE_ENGLISH);

        bluetoothPrinter.setPrinter(BluetoothPrinter.COMM_ALIGN, BluetoothPrinter.COMM_ALIGN_CENTER);
        String poweredBy = "==============================\n"
                +""+sb.getPoweredBy()+"\n"
                +"==============================\n\n";

        bluetoothPrinter.setCharacterMultiple(0,0);

        bluetoothPrinter.printText(sb.getFooter()+"\n");

        bluetoothPrinter.printText(poweredBy);

//        byte[] powered = com.printer.Printer.printfont(poweredBy + "\n",
//                FontDefine.FONT_24PX, FontDefine.Align_CENTER, (byte) 0x1A, PocketPos.LANGUAGE_ENGLISH);

//        byte[] totalByte = new byte[header.length+subHeader.length+body.length+footer.length+powered.length];

//        int offset = 0;
//        System.arraycopy(header, 0,totalByte , offset, header.length);
//        offset += header.length;
//
//        System.arraycopy(subHeader,0,totalByte,offset,subHeader.length);
//        offset += subHeader.length ;
//
//        System.arraycopy(body,0,totalByte,offset,body.length);
//        offset += body.length ;
//
//        System.arraycopy(footer,0,totalByte,offset,footer.length);
//        offset += footer.length ;
//
//        System.arraycopy(powered,0,totalByte,offset,powered.length);


//        try{
//            if(mConnector != null) {
//                mConnector.sendData(totalByte);
//            }else{
//
//                showToast("Please Connect Printer");
//            }
//        }catch (P25ConnectionException e) {
//            e.printStackTrace();
//            return false;
//        }

        bluetoothPrinter.setPrinter(BluetoothPrinter.COMM_PRINT_AND_WAKE_PAPER_BY_LINE, 1);


        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("operation", "printing");
            jsonObject.put("status","printed");

            PluginResult result = new PluginResult(PluginResult.Status.OK, jsonObject);
			result.setKeepCallback(false);
			PaypadFacade.callbackContext.sendPluginResult(result);

        }catch(JSONException ex){
            
        }

        return true;
    }
    private String format(String text, int length, boolean equalPadding){

        int len = text.length();

        String temp ="";

        if(length < len)
            return text;

        if(equalPadding == true){

            int mid = (length - len) /2 ;

            for(int i = 0; i < mid; i++){

                temp += " ";
            }

            temp += text;

            for(int i=0; i < mid; i++){
                temp += " ";
            }
        }else{
            temp = format(text,length);
        }

        return temp;
    }

    private String format(String text,int length){

        String temp = text;

        for(int i = 0; i < length-text.length(); i++){
            temp += " ";
        }
        return temp;
    }


	public void trace(String msg) {
		Log.d("baseactivity", msg);
//		toast(msg);
	}

//	public void toast(String msg) {
//		Toast.makeText(Globals.context, msg, Toast.LENGTH_SHORT).show();
//	}

	@Override
	public void onDestroy() {
		stop();
		Log.d("Printer Service", "Destroyed");
		super.onDestroy();
	}

	private void sendMsg(int flag) {
		Message msg = new Message();
		msg.what = flag;
		handler.sendMessage(msg);
	}

	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {//
			if (!Thread.currentThread().isInterrupted()) {
				switch (msg.what) {
				case 3:

					break;

				case 4:

					break;
				case 5:
					break;

				case -1:
					break;
				}
			}
			super.handleMessage(msg);
		}

	};
	
	@Override
	public IBinder onBind(Intent intent) {
//	    mHandler = ((MyApplication) getApplication()).getHandler();
	    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		mState = STATE_NONE;
	    return mBinder;
	}

//	public class LocalBinder extends Binder {
//	    public BluetoothService getService() {
//	        return BluetoothService.this;
//	    }
//	}
	
	private final IBinder mBinder = new LocalBinder();

//    private void showToast(String message) {
//        Toast.makeText(Globals.context, message, Toast.LENGTH_SHORT).show();
//    }

//    private void connect(BluetoothDevice device) {
//
//        if (device.getBondState() == BluetoothDevice.BOND_NONE) {
//            try {
//                createBond(device);
//            } catch (Exception e) {
//                showToast("Failed to pair device");
//
//                return;
//            }
//        }
//
//        try {
//            if (!mConnector.isConnected()) {
//                mConnector.connect(device);
//            } else {
//                mConnector.disconnect();
//
////                showDisonnected();
//            }
//        } catch (P25ConnectionException e) {
//            e.printStackTrace();
//        }
//    }

    private void createBond(BluetoothDevice device) throws Exception {

        try {
            Class<?> cl 	= Class.forName("android.bluetooth.BluetoothDevice");
            Class<?>[] par 	= {};

            Method method 	= cl.getMethod("createBond", par);

            method.invoke(device);

        } catch (Exception e) {
            e.printStackTrace();

            throw e;
        }
    }
}
