package com.datecs.lineaservice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

import com.datecs.linea.LineaPro;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

/**
 * This class allows you to access the state of service that communicate with Linea device.
 */
public class LineaManager {

    private class LineaReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (LineaService.ACTION_ACCESSORY_DEBUG.equals(action)) {
                debugLinea(intent.getStringExtra(Intent.EXTRA_TEXT));
            } else if (LineaService.ACTION_ACCESSORY_ATTACHED.equals(action)) {
                connectLinea();
            } else if (LineaService.ACTION_ACCESSORY_DETACHED.equals(action)) {
                disconnectLinea(true);
            }
        }
    }

    private final LineaReceiver mReceiver = new LineaReceiver();

    private LineaConnection mConnection;

    private Socket mClientSocket;

    private LineaPro mLineaPro;

    /**
     * Constructs a new instance of this class.
     */
    public LineaManager() {
        // LineaPro.setDebug(true);
    }

    /**
     *
     * @param message
     */
    private void debugLinea(String message) {
        mConnection.onLineaDebug(message);
    }

    /**
     *
     */
    private void connectLinea() {
        mLineaPro = null;

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                SocketAddress address = new InetSocketAddress("127.0.0.1", LineaService.SERVER_PORT);

                try {
                    mClientSocket = new Socket();
                    mClientSocket.setTcpNoDelay(true);
                    mClientSocket.connect(address, 1000);
                    if (mClientSocket.isConnected()) {
                        mLineaPro = new LineaPro(mClientSocket.getInputStream(),
                                mClientSocket.getOutputStream());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    synchronized (LineaManager.this) {
                        LineaManager.this.notify();
                    }
                }
            }
        });
        thread.start();

        synchronized (LineaManager.this) {
            try {
                LineaManager.this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        if (mLineaPro != null) {
            mConnection.onLineaConnected(mLineaPro);
        } else {
            // Nothing to do here
        }
    }

    /**
     *
     * @param notify
     */
    private void disconnectLinea(boolean notify) {
        if (mClientSocket != null) {
            try {
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (mLineaPro != null) {
            try {
                mLineaPro.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (notify) {
                mConnection.onLineaDisconnected(mLineaPro);
            }

            mLineaPro = null;
        }
    }

    /**
     *
     * @param context
     * @param connection
     */
    public void bindService(Context context, LineaConnection connection) {
        IntentFilter intentFilter = new IntentFilter(LineaService.ACTION_ACCESSORY_ATTACHED);
        intentFilter.addAction(LineaService.ACTION_ACCESSORY_DETACHED);
        intentFilter.addAction(LineaService.ACTION_ACCESSORY_DEBUG);
        context.registerReceiver(mReceiver, intentFilter);
        mConnection = connection;
        connectLinea();
    }

    /**
     *
     * @param context
     */
    public void unbindService(Context context) {
        context.unregisterReceiver(mReceiver);
        disconnectLinea(true);
    }

    /**
     * Return where Linea connection is established.
     * @return true if connection is established.
     */
    public boolean isConnected() {
        return mLineaPro != null;
    }

    /**
     * Get instance to connected Linea device.
     * @return instance to Linea device or null if connection is not established.
     */
    public LineaPro getLineaPro() {
        return mLineaPro;
    }
}
