/*
 * ----------------------------------------------------------------------------
 *  (C) Copyright Testing Technologies, 2001-2015.  All Rights Reserved.
 *
 *  All copies of this program, whether in whole or in part, and whether
 *  modified or not, must display this and all other embedded copyright
 *  and ownership notices in full.
 *
 *  See the file COPYRIGHT for details of redistribution and use.
 *
 *  You should have received a copy of the COPYRIGHT file along with
 *  this file; if not, write to the Testing Technologies,
 *  Michaelkirchstr. 17/18, 10179 Berlin, Germany.
 *
 *  TESTING TECHNOLOGIES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 *  SOFTWARE. IN NO EVENT SHALL TESTING TECHNOLOGIES BE LIABLE FOR ANY
 *  SPECIAL, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 *  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 *  THIS SOFTWARE.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 *  EITHER EXPRESSED OR IMPLIED, INCLUDING ANY KIND OF IMPLIED OR
 *  EXPRESSED WARRANTY OF NON-INFRINGEMENT OR THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * ----------------------------------------------------------------------------- */
package org.etsi.its.tool.testingtech;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.Socket;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.etsi.adapter.IGnssSupport;
import org.etsi.adapter.TERFactory;
import org.etsi.ttcn.tci.CharstringValue;
import org.etsi.ttcn.tri.TriStatus;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.testingtech.ttcn.tri.TriStatusImpl;

public class GnssRemoteControl implements IGnssSupport {
    
    private final String STATUS_START = "<status>";
    private final String STATUS_END = "</status>";

    private Socket soc = null;
    private static GnssRemoteControl gnssRC = null;
    
    public static GnssRemoteControl getInstance() {
        if (gnssRC == null){
            gnssRC = new GnssRemoteControl();
        }
        return gnssRC;
    }

    public TriStatus init() {
        return TriStatusImpl.OK;
    }
    
    public static void main(String[] args) {
        try {
            for (int i = 0; i < 10; i++) {
                GnssRemoteControl grc = GnssRemoteControl.getInstance();
                grc.showMessage("Now controlled by TTwborkbench");
                grc.loadScenario(0);
//            grc.getScenarioName();
//            grc.getScenarioStatus();
//            grc.getScenarioDuration();
                grc.startScenario();
//            grc.getScenarioStatus();
                Thread.sleep(2000);
                grc.stopScenario();
//            grc.getScenarioStatus();
            }
        } catch (Throwable th) {
            th.printStackTrace();
        }
        finally {
//            try {
//                if (soc!=null) {
//                    soc.close();
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
        }
    }
    
    public void dispose() {
        try {
            System.out.println("+++++++++++++++++++++++++++++++++++++++++++++");
            System.out.println("CLOSING");
            System.out.println("+++++++++++++++++++++++++++++++++++++++++++++");
            if (soc!=null) {
                soc.close();
                soc = null;
            }
            gnssRC = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private String getScenario(int p_id) throws Exception {
        String result;
        String scenario;
        
        switch (p_id) {
        case 0:
//            result = "c:\\Program Files (x86)\\Spirent Communications\\Positioning Application\\Scenarios\\C2C\\StaticPos\\StaticPos.scn";
            scenario = "GnssScenario_StaticPos";
            break;
        case 1:
//            result = "C:\\Program Files (x86)\\Spirent Communications\\Positioning Application\\Scenarios\\C2C\\DynamicPos1000m\\DynamicPos200m.scn";
            scenario = "GnssScenario_DynamicPos200m";
            break;
        case 2:
//            result = "C:\\Program Files (x86)\\Spirent Communications\\Positioning Application\\Scenarios\\C2C\\DynamicPos1000m\\DynamicPos1000m.scn";
            scenario = "GnssScenario_DynamicPos1000m";
            break;
        case 3:
//            result = "C:\\Program Files (x86)\\Spirent Communications\\Positioning Application\\Scenarios\\C2C\\DynamicPos1000m\\DynamicPos1500m.scn";
            scenario = "GnssScenario_DynamicPos1500m";
            break;
        default:
            throw new Exception(p_id + ": Unknown scenario identification");
        }
        
        try {
            result = ((CharstringValue)TERFactory.getInstance().getTaParameter(scenario)).getString();
        }
        catch (Exception e) {
            throw new Exception("Could not retrieve TA parameter " + scenario + ". Check configuration.");
        }
        
        return result;
    }
    
    public int showMessage(String msg) {
        return handleCommand("MESSAGE,TTCN-3,Info,"+msg);
    }

    public boolean loadScenario(int p_id) {
        try {
//            handleCommand("DS_ENABLE");
//            handleCommand("DS_IP,192.168.89.227");
//            handleCommand("DS_INFO");
//            handleCommand("DS_STATUS,1");
            return 2 == handleCommand("SC,"+getScenario(p_id));
        } catch (Throwable th) {
            th.printStackTrace();
            return false;
        }
    }

    public int getScenarioName() {
        return handleCommand("SC_NAME");
    }

    public int getScenarioDuration() {
        return handleCommand("SC_DURATION");
    }

    public int getScenarioStatus() {
        return handleCommand("NULL");
    }

//    public int startScenario() {
    public boolean startScenario() {
//        handleCommand("AR");
//        try {
//            Thread.sleep(5000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        int result = handleCommand("RU");
//        try {
//            Thread.sleep(5000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        if (result==4) {
            while((result = getScenarioStatus())!=5){
                //empty
            };
        }
        return result==5;
    }
    
//    public int stopScenario() {
    public boolean stopScenario() {
        return 2==handleCommand("-,EN,1");
    }
    
    private int handleCommand(String command) {
        if (soc==null) {
            try {
                String address;
                try {
                    address = ((CharstringValue)TERFactory.getInstance().getTaParameter("GnssControllerAddress")).getString();
                }
                catch (Throwable th) {
                    address = "192.168.89.106";
                }
                soc = new Socket(address, 15650);
            }
            catch (Throwable th) {
                th.printStackTrace();
                return -1;
            }
        }
        try {
            command += "\r";
            System.out.println("+++++++++++++++++++++++++++++++++++++++++++++");
            System.out.println(command);
            System.out.println("+++++++++++++++++++++++++++++++++++++++++++++");
            soc.getOutputStream().write(command.getBytes());
            soc.getOutputStream().flush();
            int read=0;
            StringBuffer sb = new StringBuffer();
            do {
                read = soc.getInputStream().read();
                sb.append(new String(new byte[] {(byte) read}));
            } while(read!='\r');
            String response = sb.toString();
            System.out.println(response);
            
            int statusStart = response.indexOf(STATUS_START);
            
            int statusEnd = response.indexOf(STATUS_END, statusStart);
            
            String status = response.substring(statusStart+STATUS_START.length(), statusEnd).trim();
            
            handleResponse(response);
            
            return Integer.valueOf(status);
        } catch (Throwable th) {
            th.printStackTrace();
            return -1;
        }
    }
    
    private void handleResponse(String response) {
        try {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            parser.parse(new ByteArrayInputStream(response.getBytes()), new DefaultHandler() {
                private boolean inStatus;
                private boolean inData;
                private boolean inError;
                private boolean inFatal;
                StringBuffer sb =  new StringBuffer();;
                
                /* (non-Javadoc)
                 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
                 */
                @Override
                public void characters(char[] ch, int start, int length)
                        throws SAXException {
                    if (inStatus || inData || inError || inFatal) {
                        sb.append(ch, start, length);
                    }
                    super.characters(ch, start, length);
                }
                
                /* (non-Javadoc)
                 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
                 */
                @Override
                public void startElement(String uri, String localName,
                        String qName, Attributes attributes)
                        throws SAXException {
                    localName = getLocalName(localName, qName);
                    if (localName.equals("status")) {
                        inStatus=true;
                        sb.setLength(0);
                    }
                    else if (localName.equals("data")) {
                        inData=true;
                        sb.setLength(0);
                    }
                    else if (localName.equals("error")) {
                        inError=true;
                        sb.setLength(0);
                    }
                    else if (localName.equals("fatal")) {
                        inFatal=true;
                        sb.setLength(0);
                    }
                    super.startElement(uri, localName, qName, attributes);
                }
                
                @Override
                public void endElement(String uri, String localName,
                        String qName) throws SAXException {
                    localName = getLocalName(localName, qName);
                    if (localName.equals("status")) {
                        inStatus=false;
                        System.out.println("status: " + sb.toString());
                        //result = Integer.parseInt(sb.toString());
                        sb.setLength(0);
                    }
                    else if (localName.equals("data")) {
                        inData=false;
                        System.out.println("data: " + sb.toString());
                        sb.setLength(0);
                    }
                    else if (localName.equals("error")) {
                        inError=false;
                        System.out.println("error: " + sb.toString());
                        sb.setLength(0);
                    }
                    else if (localName.equals("fatal")) {
                        inFatal=false;
                        System.out.println("fatal: " + sb.toString());
                        sb.setLength(0);
                    }
                    super.endElement(uri, localName, qName);
                }
            }, null);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private String getLocalName(String localName, String qName) {
        if (localName.isEmpty()) {
            String[] nameParts = qName.split(":",2);
            if (nameParts.length==1) {
                localName = nameParts[0];
            }
            else {
                localName = nameParts[1];
            }
        }
        return localName;
    }
}
