package usda.weru.soil.arssql;

import de.schlichtherle.io.File;
import de.schlichtherle.io.FileWriter;
import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.*;
import java.util.*;
import javax.swing.JOptionPane;
import org.apache.log4j.Logger;
import usda.weru.util.Util;

/**
 * Telnet - connect to a given host and service
 * This does not hold a candle to a real Telnet client, but
 * shows some ideas on how to implement such a thing.
 * @version $Id: CommunicateWithARS.java,v 1.9 2008-05-19 20:49:36 wjr Exp $
 */
public class CommunicateWithARS {
    private static final Logger LOGGER = Logger.getLogger(CommunicateWithARS.class);
    static String[] args = {"sdmdataaccess.nrcs.usda.gov", "80"};
    
    int portNum = 80;
    Vector<String> toVec = new Vector();
    SAXParse doc;
    Thread readThread=null;

    CommunicateWithARS() {
    }
    public SAXParse getXMLDoc() {
        try {
            while (readThread.isAlive()) {
                Thread.sleep(10);
            }
        } catch (Exception e) {
            Logger.getLogger(CommunicateWithARS.class).info("getXMLDoc interrupted", e);
        }
        return doc;
    }

    CommunicateWithARS(String server, String query) {
        
        hdr[1] = "Host: " + server;
        body[0] = "SOAPAction: \"http://" + server + "/Tabular/SDMTabularService.asmx/RunQuery\"";
        body[6] = "      <Query>" + query + "</Query>";
        try {
            talkTo(args[0]);            
        } 
        catch(ConnectException ce){
            LOGGER.warn("Unable to connect to soil datamart.  Internet access may be down.", ce);
                EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    JOptionPane.showMessageDialog(null, "Unable to connect to Soil Datamart.\n\nVerify your internet connection is working.", "Connection Error", JOptionPane.ERROR_MESSAGE);
                }
            });
        }
        catch (IOException ioe) {
            Logger.getLogger(CommunicateWithARS.class).error("talkTo failed", ioe);
            
                        
                EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    JOptionPane.showMessageDialog(null, "Unable to communicate with Soil Datamart.\n\nVerify your internet connection is working.", "Communications Error", JOptionPane.ERROR_MESSAGE);
                }
            });
        }
    }

    public static void main(String[] argv) throws IOException {
        new CommunicateWithARS().talkTo(args[0]);
    }

    private void addCmdLines(Vector toVec) {
        int len=0;
        for (int idx=0; idx < body.length; idx++) {
            len+=body[idx].length() + 1;
        }
        hdr[3]+="" + len;

        for (int idx=0; idx < hdr.length; idx++) {
            toVec.add(hdr[idx]);
        }
        for (int idx=0; idx < body.length; idx++) {
            toVec.add(body[idx]);
        }
        for (int idx=0; idx < 3; idx++) {
            toVec.add(blanks);
        }
    }

    private void talkTo(final String host) throws IOException {
        addCmdLines(toVec);
            try{
                Socket s = new Socket(host, portNum);
                readThread=new PipeFromServer(s.getInputStream(), System.out, this.body[6]);
                readThread.start();

                // Connect our stdin to the remote
    //			new Pipe(System.in, s.getOutputStream()).start();
                // Connect the remote to our stdout
                new PipeToServer(toVec, s.getOutputStream()).start();
            }
            catch(UnknownHostException uhe){
                LOGGER.warn("Unable to resolve soil datamart host.  Internet access may be down.", uhe);
                EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    JOptionPane.showMessageDialog(null, String.format("Unable to resolve Soil Datamart host:\n%s\n\nVerify your internet connection is working.", host), "Unknown Host", JOptionPane.ERROR_MESSAGE);
                }
            });
            }
            
            
    }


    /* This class handles one half of a full-duplex connection.
     * Line-at-a-time mode.
     */
    class PipeFromServer extends Thread {
        BufferedReader bis;
//        PrintStream os;
//        InputStream is;
        String tableName;

        /** Construct a Pipe to read from is and write to os */
        PipeFromServer(InputStream is, OutputStream os, String qStr) {
//            this.is=is;
            this.bis=new BufferedReader(new InputStreamReader(is));
//            this.os=new PrintStream(os);
            this.tableName=qStr;
            tableName=tableName.substring(tableName.indexOf(" FROM ") + 6).trim();
            int a =tableName.indexOf(" ");
            a = a < 0 ? Integer.MAX_VALUE : a;
            int b = tableName.indexOf("</");
            b = b < 0 ? Integer.MAX_VALUE : b;
            tableName=tableName.substring(0, Math.min(a, b)).trim();
//            System.out.println("tableName " + tableName);
        }

        /** Do the reading and writing. */
        public void run() {
            String line;
            String filNam="tmpsoil/soil.xml";

//            File tmpdirf = new File("tmpsoil");
//            if (!tmpdirf.exists()) {        // make a tmp directory if it doesn't exist
//                while (!tmpdirf.mkdir()) {
//                    tmpdirf = new File(tmpdirf.getName() + "$");
//                }
//            }
            try {
                File tmpf;
                tmpf=new File(File.createTempFile(tableName, ".xml"));
                tmpf.deleteOnExit();
                filNam=tmpf.getAbsolutePath();
            } catch (IOException ioe) {
            Logger.getLogger(CommunicateWithARS.class).error("can't create temp file", ioe);
            }


            try {
                long length = 0;
                while (true) {
                    line=bis.readLine();
                    if(line == null){
                        continue;
                    }
                    else if (line.trim().toLowerCase().startsWith("content-length")){
                        String[] parts = line.split(":");
                        length = Long.parseLong(parts[1].trim());
                    }
                    else if(line.trim().length() == 0)
                    {
//                        bis.readLine();             // throw away blank line\
                        
                        PrintWriter outf=new PrintWriter(new BufferedWriter(new FileWriter(filNam)));
                        for (int idx=0; idx < length; idx++) {
                            int tchr=bis.read();
                            outf.print((char) tchr);
                        }
                        outf.println();
                        outf.close();
                        doc=SAXParse.parse(filNam);

                        return;
                    }
                    
                }
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), "Connection Error:\n" + Util.fileContents(new File(filNam)), JOptionPane.ERROR_MESSAGE);
                LOGGER.error(e);                
            }
        }
    }

    /* This class handles one half of a full-duplex connection.
     * Line-at-a-time mode.
     */
    static class PipeToServer extends Thread {
        PrintStream os;
        Vector<String> toVec;

        /** Construct a Pipe to read from is and write to os */
        PipeToServer(Vector<String> toVec, OutputStream os) {
            this.toVec=toVec;
            this.os=new PrintStream(os);
        }

        /** Do the reading and writing. */
        public void run() {
            String line;
            for (Iterator tvi=toVec.iterator(); tvi.hasNext();) {
                line=(String) tvi.next();
                if (line == null) {
                    return;
                }
                os.print(line + "\r\n");
                os.flush();
            }
        }
    }
    String[] body={"SOAPAction: \"http://SDMDataAccess.nrcs.usda.gov/Tabular/SDMTabularService.asmx/RunQuery\"",
        "",
        "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
        "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">",
        "  <soap:Body>",
        "    <RunQuery xmlns=\"http://SDMDataAccess.nrcs.usda.gov/Tabular/SDMTabularService.asmx\">",
        "      <Query>SELECT lkey,areasymbol,areaname FROM legend ORDER BY areasymbol</Query>",
        //                  "      <Query>SELECT mukey,musym,muname FROM mapunit WHERE lkey = '11231' ORDER BY muname</Query>",
        "    </RunQuery>",
        "  </soap:Body>",
        "</soap:Envelope>",
        //                  "                                                                       \n";
        ""
    };
    String blanks="                         \n";
    String[] hdr={"POST /Tabular/SDMTabularService.asmx HTTP/1.1",
        "Host: SDMDataAccess.nrcs.usda.gov",
        "Content-Type: text/xml; charset=utf-8",
        "Content-Length: "
    };
}

