/*
 * Copyright
 *   2009 axYus - www.axyus.com
 *   2009 C.Marchand - christophe.marchand@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package fr.gouv.finances.dgfip.xemelios.batch;

import fr.gouv.finances.dgfip.xemelios.data.impl.pool.PoolManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;
import java.util.Timer;
import org.apache.log4j.Logger;

/**
 *
 * @author chm
 */
public class StopServer {
    private static final Logger logger = Logger.getLogger(StopServer.class);
    private int port = 0;
    private Timer timer;
    private ServerSocket ss;
    private String[] allowedStoppers;
    protected boolean listening = true;

    public StopServer(int port, Timer timer, String allowedStoppers) {
        super();
        this.port = port;
        this.timer=timer;
        StringTokenizer st = new StringTokenizer(allowedStoppers, ",");
        this.allowedStoppers = new String[st.countTokens()];
        for(int i=0;i<st.countTokens();i++) {
            this.allowedStoppers[i] = st.nextToken();
        }
    }

    public void start() throws Exception {
        Thread starter = new Thread() {
            public void run() {
                try {
                    ss = new ServerSocket(port);
                    int count = 0;
                    while(listening) {
                        if(listening) {
                            ++count;
                            try {
                                new StopServerThread(ss.accept(),StopServer.this,allowedStoppers).start();
                            } catch(Exception ex) {
                                // throwed when ss has been closed
                            }
                        }
                    }
                    if(!ss.isClosed()) ss.close();
                } catch(IOException ioEx) {
                    System.err.println("Another instance is already running.");
                    System.exit(2);
                }
            }
        };
        starter.start();
    }
    protected void stop() {
        System.out.println("stopping");
        listening=false;
        timer.cancel();
        timer.purge();
        PoolManager.getInstance().shutdown();
        System.exit(1);
    }

    private class StopServerThread extends Thread {
        private Socket so;
        private StopServer instance;
        private String[] allowedStoppers;
        public StopServerThread(Socket so, StopServer instance, String[] allowedStoppers) {
            super();
            this.so=so;
            this.instance=instance;
            this.allowedStoppers=allowedStoppers;
        }
        public void run() {
            try {
                PrintWriter out = new PrintWriter(so.getOutputStream(),true);

                BufferedReader in = new BufferedReader(new InputStreamReader(so.getInputStream()));

                String inputLine, outputLine;
                if(isAcceptedStopper(so.getInetAddress().getHostAddress())) {
                    logger.info("received stop order from "+so.getInetAddress().getHostAddress());
                    Protocol kkp = new Protocol();
                    outputLine = kkp.processInput(null);
                    out.println(outputLine);

                    while ((inputLine = in.readLine()) != null) {
                        outputLine = kkp.processInput(inputLine);
                        out.println(outputLine);
                        if (outputLine.startsWith("+OK Bye.")) {
                            instance.stop();
                            break;
                        }
                    }
                } else {
                    out.println("-ERR Unauthorized stopper, allowed are: "+allowedStoppers+", found "+so.getInetAddress().getHostAddress());
                }
                out.close();
                in.close();
                so.close();
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        }

        protected boolean isAcceptedStopper(String address) {
            boolean ret = false;
            for(String s:allowedStoppers) {
                if("*".equals(s)) {
                    ret = true;
                    break;
                } else if(s.equals(address)) {
                    ret = true;
                    break;
                }
            }
            return ret;
        }
    }

    private class Protocol {
        private static final String WELCOME_STRING = "+OK Welcome on Xemelios batch stopper";
        public String processInput(String input) {
            if(input==null) {
                return WELCOME_STRING;
            } else {
                if("stop".equals(input)) {
                    return "+OK Bye.";
                } else {
                    return "-ERR Unknown command.";
                }
            }
        }
    }
}
