import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeSet;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Sample service implementation for use with Windows Procrun.
 * <p>
 * Use the main() method for running as a Java (external) service.
 * Use the start() and stop() methods for running as a JVM (in-process) service
 */
public class ProcrunService implements Runnable {

    private static final int DEFAULT_PAUSE = 60; // Wait 1 minute
    private static final long MS_PER_SEC = 1000L; // Milliseconds in a second

    private static volatile Thread thrd; // start and stop are called from different threads

    private final long pause; // How long to pause in service loop

    private final File stopFile;

    /**
     *
     * @param wait seconds to wait in loop
     * @param file optional file - if non-null, run loop will stop when it disappears
     */
    private ProcrunService(long wait, File file) {
        pause=wait;
        stopFile = file;
    }

    private static File tmpFile(String fileName) {
        return new File(System.getProperty("java.io.tmpdir"),
                fileName != null ? fileName : "ProcrunService.tmp");
    }

    private static void usage(){
        System.err.println("Must supply the argument 'start' or 'stop'");
    }

    /**
     * Helper method for process args with defaults.
     *
     * @param args array of string arguments, may be empty
     * @param argnum which argument to extract
     * @return the argument or null
     */
    private static String getArg(String[] args, int argnum){
        if (args.length > argnum) {
            return args[argnum];
        } else {
            return null;
        }
    }

    private static void logSystemEnvironment()
    {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null)
            log("Missing currentThread context ClassLoader");
        else
            log("Using context ClassLoader : " + cl.toString());
        log("Program environment: ");

        Map<String,String> em = System.getenv();
        TreeSet<String> es = new TreeSet<>(em.keySet());
        for (Iterator<String> i = es.iterator(); i.hasNext();) {
            String n = i.next();
            log(n + " ->  " + em.get(n));
        }

        log("System properties: ");
        Properties ps = System.getProperties();
        TreeSet<Object> ts = new TreeSet<>(ps.keySet());
        for (Iterator<Object> i = ts.iterator(); i.hasNext();) {
            String n = (String)i.next();
            log(n + " ->  " + ps.get(n));
        }

        log("Network interfaces: ");
        log("LVPMU (L)oopback (V)irtual (P)ointToPoint (M)multicastSupport (U)p");
        try {
            for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements();) {
                NetworkInterface n = e.nextElement();
                char [] flags = { '-', '-', '-', '-', '-'};
                if (n.isLoopback())
                    flags[0] = 'x';
                if (n.isVirtual())
                    flags[1] = 'x';
                if (n.isPointToPoint())
                    flags[2] = 'x';
                if (n.supportsMulticast())
                    flags[3] = 'x';
                if (n.isUp())
                    flags[4] = 'x';
                String neti = new String(flags) + "   " + n.getName() + "\t";
                for (Enumeration<NetworkInterface> i = n.getSubInterfaces(); i.hasMoreElements();) {
                    NetworkInterface s = i.nextElement();
                    neti += " [" + s.getName() + "]";
                }
                log(neti + " -> " + n.getDisplayName());
                List<InterfaceAddress> i = n.getInterfaceAddresses();
                if (!i.isEmpty()) {
                    for (int x = 0; x < i.size(); x++) {
                        InterfaceAddress a = i.get(x);
                        log("        " + a.toString());
                    }
                }
            }
        } catch (SocketException e) {
            // Ignore
        }
    }

    /**
     * Common entry point for start and stop service functions.
     * To allow for use with Java mode, a temporary file is created
     * by the start service, and a deleted by the stop service.
     *
     * @param args [start [pause time] | stop]
     * @throws IOException if there are problems creating or deleting the temporary file
     */
    public static void main(String[] args) throws IOException {
        final int argc = args.length;
        log("ProcrunService called with "+argc+" arguments from thread: "+Thread.currentThread());
        for(int i=0; i < argc; i++) {
            System.out.println("["+i+"] "+args[i]);
        }
        String mode=getArg(args, 0);
        if ("start".equals(mode)){
            File f = tmpFile(getArg(args, 2));
            log("Creating file: "+f.getPath());
            f.createNewFile();
            startThread(getArg(args, 1), f);
        } else if ("stop".equals(mode)) {
            final File tmpFile = tmpFile(getArg(args, 1));
            log("Deleting file: "+tmpFile.getPath());
            tmpFile.delete();
        } else {
            usage();
        }
    }

    /**
     * Start the JVM version of the service, and waits for it to complete.
     *
     * @param args optional, arg[0] = timeout (seconds)
     */
    public static void start(String [] args) {
        startThread(getArg(args, 0), null);
        while(thrd.isAlive()){
            try {
                thrd.join();
            } catch (InterruptedException ie){
                // Ignored
            }
        }
    }

    private static void startThread(String waitParam, File file) {
        long wait = DEFAULT_PAUSE;
        if (waitParam != null) {
            wait = Integer.valueOf(waitParam).intValue();
        }
        log("Starting the thread, wait(seconds): " + wait);
        thrd = new Thread(new ProcrunService(wait * MS_PER_SEC, file));
        thrd.start();
    }

    /**
     * Stop the JVM version of the service.
     *
     * @param args ignored
     */
    public static void stop(String [] args){
        if (thrd != null) {
            log("Interrupting the thread");
            thrd.interrupt();
        } else {
            log("No thread to interrupt");
        }
    }

    /**
     * This method performs the work of the service.
     * In this case, it just logs a message every so often.
     */
    @Override
    public void run() {
        log("Started thread in "+System.getProperty("user.dir"));
        logSystemEnvironment();
        while(stopFile == null || stopFile.exists()){
            try {
                log("pausing...");
                Thread.sleep(pause);
            } catch (InterruptedException e) {
                log("Exitting");
                break;
            }
        }
    }

    private static void log(String msg){
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
        System.out.println(df.format(new Date())+msg);
    }

    @Override
    protected void finalize(){
        log("Finalize called from thread "+Thread.currentThread());
    }
}
