public class ApiKey extends Communication {
    private String apikey = "";

    public ApiKey(String apikey) {
        this.apikey = apikey;
    }

    @Override
    public String getCommand() {
        return "apikey:{" + apikey + "}";
    }
} public abstract class Communication {
    private static String TAG = "Communication";

    public static final String RESPOND_ERROR = "error";
    public static final String RESPOND_OK = "ok";
    public static final String RESPOND_BUSY = "busy ";
    public static final String RESPOND_NOT_LOCKED = "not locked";

    protected String command;

    public String getCommand() {
        return command;
    }

    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        return response.equals(Communication.RESPOND_OK);
    }

    public boolean isDelayNeeded() {
        return false;
    }
} public class Exit extends Communication {

    public static final String RESPOND_SUCCESS = "Goodbye!";

    @Override
    public String getCommand() {
        return "exit";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        return response.equals(Exit.RESPOND_SUCCESS);
    }
} public class GetBrightness extends Communication {

    @Override
    public String getCommand() {
        return "getbrightness";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "brightness:";
        if (response.contains(prefix)) {
            int brightness = Integer.valueOf(response.substring(response.indexOf(prefix)+prefix.length()));
            RemoteState.getInstance().setBrightness(brightness);
            return true;
        }
        return false;
    }
} public class GetColors extends Communication {
    @Override
    public String getCommand() {
        return "getcolors";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "colors:";
        if (response.contains(prefix)) {
            response = response.replaceAll("[^0-9]+", " ");
            List<String> allNumbers = Arrays.asList(response.trim().split(" "));

            ArrayList<Integer> colors = new ArrayList<>();
            int[] color = new int[3];
            for (int i = 0; i < allNumbers.size(); i += 4) {
                color[0] = Integer.valueOf(allNumbers.get(i+1));
                color[1] = Integer.valueOf(allNumbers.get(i+2));
                color[2] = Integer.valueOf(allNumbers.get(i+3));

                colors.add(UiHelper.toColorInt(color));
            }
            RemoteState.getInstance().setColors(colors);
            return true;
        }
        return false;
    }
} public class GetCountLeds extends Communication {
    @Override
    public String getCommand() {
        return "getcountleds";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "countleds:";
        if (response.contains(prefix)) {
            int ledCount = Integer.valueOf(response.substring(response.indexOf(prefix)+prefix.length()));
            RemoteState.getInstance().setCountLeds(ledCount);
            return true;
        }
        return false;
    }
} public class GetGamma extends Communication {

    @Override
    public String getCommand() {
        return "getgamma";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "gamma:";
        if (response.contains(prefix)) {
            double gamma = Double.valueOf(response.substring(response.indexOf(prefix)+prefix.length()));
            RemoteState.getInstance().setGamma(gamma);
            return true;
        }
        return false;
    }
} public class GetLeds extends Communication {
    @Override
    public String getCommand() {
        return "getleds";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "leds:";
        if (response.contains(prefix)) {
            response = response.replaceAll("[^0-9]+", " ");
            List<String> allNumbers = Arrays.asList(response.trim().split(" "));

            ArrayList<Rect> leds = new ArrayList<>();
            for (int i = 0; i < allNumbers.size(); i += 5) {
                int left = Integer.valueOf(allNumbers.get(i+1));
                int top = Integer.valueOf(allNumbers.get(i+2));
                int right = left + Integer.valueOf(allNumbers.get(i+3));
                int bottom = top + Integer.valueOf(allNumbers.get(i+4));
                Rect r = new Rect(left, top, right, bottom);
                leds.add(r);
            }
            RemoteState.getInstance().setLeds(leds);
            return true;
        }
        return false;
    }
} public class GetMode extends Communication {

    public static final String RESPOND_AMBILIGHT = "mode:ambilight";
    public static final String RESPOND_MOODLAMP = "mode:moodlamp";

    @Override
    public String getCommand() {
        return "getmode";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        RemoteState.Mode currentMode;
        switch(response) {
            case RESPOND_AMBILIGHT:
                currentMode = RemoteState.Mode.AMBILIGHT;
                break;
            case RESPOND_MOODLAMP:
                currentMode = RemoteState.Mode.MOODLAMP;
                break;
            default:
                return false;
        }
        RemoteState.getInstance().setMode(currentMode);
        return true;
    }
} public class GetProfile extends Communication {
    private static String TAG = "GetStatus";
    public static final String RESPOND_ON = "status:on";

    @Override
    public String getCommand() {
        return "getprofile";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "profile:";
        if (response.contains(prefix)) {
            String profile = response.substring(response.indexOf(prefix)+prefix.length());
            RemoteState.getInstance().setProfile(profile);
            return true;
        }
        return false;
    }
} public class GetProfiles extends Communication {
    @Override
    public String getCommand() {
        return "getprofiles";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "profiles:";
        if (response.contains(prefix)) {
            response = response.substring(response.indexOf(prefix)+prefix.length());
            ArrayList<String> list = new ArrayList(Arrays.asList(response.split(";")));
            RemoteState.getInstance().setProfiles(list);
            return true;
        }
        return false;
    }
} public class GetSmoothness extends Communication {

    @Override
    public String getCommand() {
        return "getsmooth";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        String prefix = "smooth:";
        if (response.contains(prefix)) {
            int smooth = Integer.valueOf(response.substring(response.indexOf(prefix)+prefix.length()));
            RemoteState.getInstance().setSmoothness(smooth);
            return true;
        }
        return false;
    }
} public class GetStatus extends Communication {
    private static String TAG = "GetStatus";
    public static final String RESPOND_ON = "status:on";
    public static final String RESPOND_OFF = "status:off";

    @Override
    public String getCommand() {
        return "getstatus";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        RemoteState.Status currentStatus;
        switch(response) {
            case RESPOND_ON:
                currentStatus = RemoteState.Status.ON;
                break;
            case "status:off":
                currentStatus = RemoteState.Status.OFF;
                break;
            case "status:device error":
                currentStatus = RemoteState.Status.DEVICE_ERROR;
                break;
            case "status:unknown":
            default:
                currentStatus = RemoteState.Status.UNKNOWN;
        }
        RemoteState.getInstance().setStatus(currentStatus);

        return response.equals(RESPOND_ON) || response.equals(RESPOND_OFF);
    }
} public class Lock extends Communication {

    public static final String RESPOND_SUCCESS = "lock:success";

    @Override
    public String getCommand() {
        return "lock";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        return response.equals(Lock.RESPOND_SUCCESS);
    }
} public class SetBrightness extends Communication {

    private int brightness = -1;

    public SetBrightness(int brightness) {
        this.brightness = brightness;
    }

    @Override
    public String getCommand() {
        return "setbrightness:" + brightness;
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class SetColor extends Communication {

    private int[][] colors;
    private int singleTarget = -1;

    public SetColor(int[][] colors) {
        this.colors = colors;
    }

    public SetColor(int singleTarget, int[] color) {
        this.singleTarget = singleTarget;
        this.colors[singleTarget] = color;
    }

    @Override
    public String getCommand() {
        String command = "setcolor:";
        if (singleTarget != -1)
            return command + getSingleLedString(singleTarget);

        for (int i = 0; i < colors.length;i++) {
            command = command + getSingleLedString(i);
        }
        return command;
    }

    private String getSingleLedString(int pos) {
        return (pos+1) + "-" + colors[pos][0] + "," + colors[pos][1] + "," + colors[pos][2] + ";";
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class SetGamma extends Communication {

    private double gamma = -1.0;

    public SetGamma(double gamma) {
        this.gamma = gamma;
    }

    @Override
    public String getCommand() {
        return "setgamma:" + gamma;
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class SetLeds extends Communication {

    private Rect[] rects;

    public SetLeds(Rect[] rects) {
        this.rects = rects;
    }

    @Override
    public String getCommand() {
        String command = "setleds:";

        for (int i = 0; i < rects.length; i++) {
            command = command + getSingleLedString(i);
        }
        return command;
    }

    private String getSingleLedString(int pos) {
        return (pos+1) + "-" + rects[pos].left + "," + rects[pos].top + "," + rects[pos].width() + "," + rects[pos].height() + ";";
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class SetProfile extends Communication {

    private String profile = "";

    public SetProfile(String profile) {
        this.profile = profile;
    }

    @Override
    public String getCommand() {
        return "setprofile:" + profile;
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class SetSmoothness extends Communication {

    private int smoothness = -1;

    public SetSmoothness(int smoothness) {
        this.smoothness = smoothness;
    }

    @Override
    public String getCommand() {
        return "setsmooth:" + smoothness;
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class ToggleMode extends Communication {
    public static final String AMBILIGHT = "ambilight";
    public static final String MOODLAMP = "moodlamp";
    protected boolean needsDelay = true;

    @Override
    public String getCommand() {
        String command = "setmode:";
        if (RemoteState.getInstance().getMode() == RemoteState.Mode.AMBILIGHT) {
            command = command + MOODLAMP;
        } else {
            command = command + AMBILIGHT;
        }
        return command;
    }

} public class ToggleStatus extends Communication {
    private static String TAG = "ToggleStatus";

    @Override
    public String getCommand() {
        String command = "setstatus:on";
        if (RemoteState.getInstance().getStatus() == RemoteState.Status.ON) {
            command = "setstatus:off";
        }
        return command;
    }

    @Override
    public boolean isDelayNeeded() {
        return true;
    }
} public class Unlock extends Communication {

    public static final String RESPOND_SUCCESS = "unlock:success";

    @Override
    public String getCommand() {
        return "unlock";
    }

    @Override
    public boolean onRespond(String response, Communicator.OnCompleteListener listener ) {
        return response.equals(Unlock.RESPOND_SUCCESS);
    }
} public class NetworkHelper {

    public final static int DEFAULT_PORT = 3636;
    public final static int DEFAULT_TIMEOUT = 200;

    private static final ExecutorService es = Executors.newFixedThreadPool(255);

    public static Communicator getCommunicator(Context context) {
        return ((GlobalVars) context.getApplicationContext()).getCommunicator();
    }

    public static boolean isValidNetwork(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();
        for (NetworkInfo ni : netInfo) {
            if (ni.getTypeName().equalsIgnoreCase("WIFI"))
                if (ni.isConnected())
                    return true;
            if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
                if (ni.isConnected())
                    return false;
        }
        return false;
    }

    public static boolean hasAPIConnection(Context context) {
        try {
            NetworkHelper.getCommunicator(context).refreshState(null);
            return true;
        } catch (Exception e) {
            // TODO: Make work with Waiting without blocking. Threading..
            //UiHelper.showAlert(this, e.getMessage());
            return false;
        }
    }

    public static String getAvaiableConnection(Context context) {
        for( int i = 1; i < 255; i++) {
            String ip = getNetPartOfIpAddress(context) + i;
            Future<String> future = findSocket(ip, DEFAULT_PORT);
            Log.d("Avaibles Connections", "" + i);
            try {
                if (future.get() != null) {
                    return future.get();
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static String getNetPartOfIpAddress(Context context) {
        WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        wm.getConnectionInfo().getNetworkId();
        String ip = Formatter.formatIpAddress(wm.getConnectionInfo().getIpAddress());
        ip = ip.substring(0, ip.lastIndexOf('.')+1);
        return ip;
        // TODO: get subnetmask and build net address
    }

    public static Future<String> findSocket(final String ip, final int port) {
        return es.submit(new Callable<String>() {
            @Override
            public String call() {
                try {
                    Socket socket = new Socket();
                    socket.connect(new InetSocketAddress(ip, port), DEFAULT_TIMEOUT);
                    socket.close();
                    // es.shutdown();
                    return ip;
                } catch (Exception ex) {
                    return null;
                }
            }
        });
    }

}
import android.graphics.Rect;
import android.util.Log;
import com.jraska.console.Console;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import de.prismatikremote.hartz.prismatikremote.backend.commands.ApiKey;
import de.prismatikremote.hartz.prismatikremote.backend.commands.Communication;
import de.prismatikremote.hartz.prismatikremote.backend.commands.Exit;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetBrightness;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetColors;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetCountLeds;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetGamma;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetLeds;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetMode;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetProfile;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetProfiles;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetSmoothness;
import de.prismatikremote.hartz.prismatikremote.backend.commands.GetStatus;
import de.prismatikremote.hartz.prismatikremote.backend.commands.Lock;
import de.prismatikremote.hartz.prismatikremote.backend.commands.SetBrightness;
import de.prismatikremote.hartz.prismatikremote.backend.commands.SetColor;
import de.prismatikremote.hartz.prismatikremote.backend.commands.SetGamma;
import de.prismatikremote.hartz.prismatikremote.backend.commands.SetLeds;
import de.prismatikremote.hartz.prismatikremote.backend.commands.SetProfile;
import de.prismatikremote.hartz.prismatikremote.backend.commands.SetSmoothness;
import de.prismatikremote.hartz.prismatikremote.backend.commands.ToggleMode;
import de.prismatikremote.hartz.prismatikremote.backend.commands.ToggleStatus;
import de.prismatikremote.hartz.prismatikremote.backend.commands.Unlock;
import de.prismatikremote.hartz.prismatikremote.helper.NetworkHelper;
package de.prismatikremote.hartz.prismatikremote.backend;





/**
 * Created by kaiha on 08.04.2017.
 */

public class Communicator {
    private static String TAG = "Communicator";

    /**
     * Interface to inform caller that commands have finished.
     */
    // TODO: Call these methods always on gui thread.
    public interface OnCompleteListener {
        void onError(String result);
        void onStepCompleted(Communication communication);
        void onSuccess();
    }

    /**
     * DO NOT USE THIS METHOD DIRECTLY. Use "NetworkHelper.getCommunicator(context)".
     * Otherwise it might lead to multiple/different instances (on Activities and Services) of
     * Communicator and lock lights til prismatik shut down.
     * @return A Communicator.
     */
    public static Communicator getInstance() {
        return instance;
    }

    private String serverKey;
    private String serverIp;
    private int serverPort;

    // Singleton.
    private static final Communicator instance = new Communicator();

    // Keeps lock state (so lights keep color).
    private static Executor blocker;

    /**
     * Setup the Connection information.
     * @param serverIp
     * @param serverPort
     */
    public void setConnection(String serverIp, int serverPort, String serverKey) {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        if(serverKey.equals(""))
            this.serverKey = null;
        else
            this.serverKey = serverKey;
    }

    public boolean hasBlocker() {
        return blocker != null;
    }

    public void refreshState(OnCompleteListener listener) {
        ArrayList<Communication> commands = new ArrayList<>();
        commands.add(new GetStatus());
        commands.add(new GetProfiles());
        commands.add(new GetProfile());
        commands.add(new GetCountLeds());
        commands.add(new GetMode());
        commands.add(new GetColors());
        commands.add(new GetLeds());
        commands.add(new GetGamma());
        commands.add(new GetBrightness());
        commands.add(new GetSmoothness());
        //TODO: Add all get commands

        startThread(commands, listener, false);
    }

    public void togglePower(OnCompleteListener listener) {
        ArrayList<Communication> commands = new ArrayList<>();
        commands.add(new GetStatus());
        commands.add(new ToggleStatus());