package org.i2p.i2psnarkxl.tunnel;

/*
 * ProxyHttpClient.java
 *
 Copyright (C) , 2009 fwd
 
   This file is part of I2PSnarkXL.
 
   This program 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, or (at your option)
   any later version.
 
   This program 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
 */

import java.io.File;
import java.util.Properties;
import java.io.IOException;

import net.i2p.data.DataHelper;
import net.i2p.i2ptunnel.TunnelController;

import net.i2p.I2PAppContext;
import net.i2p.util.Log;



public class ProxyHttpClient{
    private Log _log = new Log(ProxyHttpClient.class);
    private I2PAppContext _context;
    private static final ProxyHttpClient _instance = new ProxyHttpClient();
    public synchronized static final ProxyHttpClient instance() { return _instance; }
    
    static private  String configFile = "i2psnarkxl-proxy.config";
    private boolean _running;
    private TunnelController controller;
    
    public static final String PROP_PROXY_description = "description";//HTTP proxy for browsing eepsites and the web";
    public static final String PROP_PROXY_i2cpHost = "i2cpHost";//127.0.0.1";
    public static final String PROP_PROXY_i2cpPort = "i2cpPort";//7654";
    public static final String PROP_PROXY_interface = "interface";//127.0.0.1";
    public static final String PROP_PROXY_listenPort = "listenPort";//44444";
    public static final String PROP_PROXY_name = "name";//eepProxy";
    public static final String PROP_PROXY_option_i2cp_closeIdleTime = "option.i2cp.closeIdleTime";//1800000";
    public static final String PROP_PROXY_option_i2cp_closeOnIdle = "option.i2cp.closeOnIdle";//true";
    public static final String PROP_PROXY_option_i2cp_delayOpen = "option.i2cp.delayOpen";//false";
    public static final String PROP_PROXY_option_i2cp_newDestOnResume = "option.i2cp.newDestOnResume";//true";
    public static final String PROP_PROXY_option_i2cp_reduceIdleTime = "option.i2cp.reduceIdleTime";//1200000";
    public static final String PROP_PROXY_option_i2cp_reduceOnIdle = "option.i2cp.reduceOnIdle";//false";
    public static final String PROP_PROXY_option_i2cp_reduceQuantity = "option.i2cp.reduceQuantity";//1";
    public static final String PROP_PROXY_option_i2p_streaming_connectDelay = "option.i2p.streaming.connectDelay";//1000";
    public static final String PROP_PROXY_option_inbound_backupQuantity = "option.inbound.backupQuantity";//1";
    public static final String PROP_PROXY_option_inbound_length = "option.inbound.length";//2";
    public static final String PROP_PROXY_option_inbound_lengthVariance = "option.inbound.lengthVariance";//1";
    public static final String PROP_PROXY_option_inbound_nickname = "option.inbound.nickname";//testProxy";
    public static final String PROP_PROXY_option_inbound_quantity = "option.inbound.quantity";//1";
    public static final String PROP_PROXY_option_outbound_backupQuantity = "option.outbound.backupQuantity";//1";
    public static final String PROP_PROXY_option_outbound_length = "option.outbound.length";//2";
    public static final String PROP_PROXY_option_outbound_lengthVariance = "option.outbound.lengthVariance";//1";
    public static final String PROP_PROXY_option_outbound_nickname = "option.outbound.nickname";//testProxy";
    public static final String PROP_PROXY_option_outbound_quantity = "option.outbound.quantity";//1";
    public static final String PROP_PROXY_option_persistentClientKey = "option.persistentClientKey";//false";
    public static final String PROP_PROXY_proxyList = "proxyList";//null";
    public static final String PROP_PROXY_sharedClient = "sharedClient";//false";
    public static final String PROP_PROXY_startOnLoad = "startOnLoad";//false";
    public static final String PROP_PROXY_type = "type";//"httpclient";
    
    /** Creates a new instance of ProxyHttpClient */
    private ProxyHttpClient() {
        _context = I2PAppContext.getGlobalContext();
        _log = _context.logManager().getLog(ProxyHttpClient.class);
    }
    
    /**
     * Load up the config data from the file
     *
     * @return properties loaded or null if there was an error
     */
    private Properties loadConfig(String configFile) {
        File cfgFile = new File(configFile);
        if (!cfgFile.exists()) {
            if (_log.shouldLog(Log.ERROR))
                _log.error("Unable to load the Properties from " + configFile);
            //return null;
        }
        
        Properties props = new Properties();
        try {
            if (cfgFile.exists()) {
                DataHelper.loadProps(props, cfgFile);
            }
            
            if (!props.containsKey(PROP_PROXY_description))
                props.setProperty(PROP_PROXY_description, "HTTP proxy for browsing eepsites and the web");
            if (!props.containsKey(PROP_PROXY_i2cpHost))
                props.setProperty(PROP_PROXY_i2cpHost, "127.0.0.1");
            if (!props.containsKey(PROP_PROXY_i2cpPort))
                props.setProperty(PROP_PROXY_i2cpPort, "7654");
            //if (!props.containsKey(PROP_PROXY_interface))
            if(true)
                props.setProperty(PROP_PROXY_interface, org.klomp.snarkxl.SnarkManager.instance().getConfig().getProperty(org.klomp.snarkxl.SnarkManager.instance().PROP_EEP_HOST));
            //if (!props.containsKey(PROP_PROXY_listenPort))
            if(true)
                props.setProperty(PROP_PROXY_listenPort, org.klomp.snarkxl.SnarkManager.instance().getConfig().getProperty(org.klomp.snarkxl.SnarkManager.instance().PROP_EEP_PORT));
            //if (!props.containsKey(PROP_PROXY_name))
            if(true)
                props.setProperty(PROP_PROXY_name, org.klomp.snarkxl.SnarkManager.instance().getNickname()+"-xlProxy");
            if (!props.containsKey(PROP_PROXY_option_i2cp_closeIdleTime))
                props.setProperty(PROP_PROXY_option_i2cp_closeIdleTime, "1800000");
            if (!props.containsKey(PROP_PROXY_option_i2cp_closeOnIdle))
                props.setProperty(PROP_PROXY_option_i2cp_closeOnIdle, "true");// ---------- ? ----- needs a longer phase of checking the behaviour
            if (!props.containsKey(PROP_PROXY_option_i2cp_delayOpen))
                props.setProperty(PROP_PROXY_option_i2cp_delayOpen, "false");
            if (!props.containsKey(PROP_PROXY_option_i2cp_newDestOnResume))
                props.setProperty(PROP_PROXY_option_i2cp_newDestOnResume, "true");
            if (!props.containsKey(PROP_PROXY_option_i2cp_reduceIdleTime))
                props.setProperty(PROP_PROXY_option_i2cp_reduceIdleTime, "1200000");
            if (!props.containsKey(PROP_PROXY_option_i2cp_reduceOnIdle))
                props.setProperty(PROP_PROXY_option_i2cp_reduceOnIdle, "false");
            if (!props.containsKey(PROP_PROXY_option_i2cp_reduceQuantity))
                props.setProperty(PROP_PROXY_option_i2cp_reduceQuantity, "1");
            if (!props.containsKey(PROP_PROXY_option_i2p_streaming_connectDelay))
                props.setProperty(PROP_PROXY_option_i2p_streaming_connectDelay, "1000");
            if (!props.containsKey(PROP_PROXY_option_inbound_backupQuantity))
                props.setProperty(PROP_PROXY_option_inbound_backupQuantity, "1");
            if (!props.containsKey(PROP_PROXY_option_inbound_length))
                props.setProperty(PROP_PROXY_option_inbound_length, "2");
            if (!props.containsKey(PROP_PROXY_option_inbound_lengthVariance))
                props.setProperty(PROP_PROXY_option_inbound_lengthVariance, "1");
            //if (!props.containsKey(PROP_PROXY_option_inbound_nickname))
            if(true)
                props.setProperty(PROP_PROXY_option_inbound_nickname, org.klomp.snarkxl.SnarkManager.instance().getNickname()+"-Proxy");
            if (!props.containsKey(PROP_PROXY_option_inbound_quantity))
                props.setProperty(PROP_PROXY_option_inbound_quantity, "1");
            if (!props.containsKey(PROP_PROXY_option_outbound_backupQuantity))
                props.setProperty(PROP_PROXY_option_outbound_backupQuantity, "1");
            if (!props.containsKey(PROP_PROXY_option_outbound_length))
                props.setProperty(PROP_PROXY_option_outbound_length, "2");
            if (!props.containsKey(PROP_PROXY_option_outbound_lengthVariance))
                props.setProperty(PROP_PROXY_option_outbound_lengthVariance, "1");
            //if (!props.containsKey(PROP_PROXY_option_outbound_nickname))
            if(true)
                props.setProperty(PROP_PROXY_option_outbound_nickname, org.klomp.snarkxl.SnarkManager.instance().getNickname()+"-Proxy");
            if (!props.containsKey(PROP_PROXY_option_outbound_quantity))
                props.setProperty(PROP_PROXY_option_outbound_quantity, "1");
            if (!props.containsKey(PROP_PROXY_option_persistentClientKey))
                props.setProperty(PROP_PROXY_option_persistentClientKey, "false");
            if (!props.containsKey(PROP_PROXY_proxyList))
                props.setProperty(PROP_PROXY_proxyList, "null");
            //if (!props.containsKey(PROP_PROXY_sharedClient))
            if(true)// just to be sure! murphy!
                props.setProperty(PROP_PROXY_sharedClient, "false");
            if (!props.containsKey(PROP_PROXY_startOnLoad))
                props.setProperty(PROP_PROXY_startOnLoad, "false");
            //if (!props.containsKey(PROP_PROXY_type))
            if(true)// just to be sure! murphy!
                props.setProperty(PROP_PROXY_type, "httpclient");
            
            
            return props;
        } catch (IOException ioe) {
            if (_log.shouldLog(Log.ERROR))
                _log.error("Error reading the Properties from " + configFile, ioe);
            return null;
        }
    }
    
    
    public void createController(){
        Properties cfg = loadConfig(configFile);
        if (cfg == null) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Unable to load the config from " + configFile);
            return;
        }
        controller = new TunnelController(cfg, "");
        if(controller != null){
            org.klomp.snarkxl.SnarkManager.instance().addMessage("XLProxy creating new controller.");
        }
    }
    
    public void startControllerTunnel(){
        if(controller == null) createController();
        if(controller != null && !_running){
            controller.startTunnel();
            _running = true;
            org.klomp.snarkxl.SnarkManager.instance().addMessage("Starting XLProxy: " + controller.getMyDestination());
        }else{
            if(controller != null){
                restartControllerTunnel();
            }
        }
    }
    public void stopControllerTunnel(){
        if(controller != null){
            controller.stopTunnel();
            _running = false;
            org.klomp.snarkxl.SnarkManager.instance().addMessage("Stopping XLProxy");
        }
    }
    public void restartControllerTunnel(){
        if(controller != null){
            controller.restartTunnel();
            _running = true;
            org.klomp.snarkxl.SnarkManager.instance().addMessage("Restarting XLProxy: " + controller.getMyDestination());
        }
    }
    public boolean isRunning(){
        return _running;
    }
    
    
    public void forceNewDestination(){
        // how long we can not force the manager to reconnect with a new destination we kill the old mannager and force a new manager on next connection
        // it's not the way i like to do this but currently i see no other option to do it.
        if(isRunning()){
            stopControllerTunnel();
            
            if(controller != null){
                controller = null;
                _running = false;
            }
            restartControllerTunnel();
            org.klomp.snarkxl.SnarkManager.instance().addMessage("XLProxy forced restarting with new destination");
        }else if(controller != null){
            controller = null;
            _running = false;
            org.klomp.snarkxl.SnarkManager.instance().addMessage("XLProxy controller forced to die");
        }
    }
    
    public void refreshSettings(){
        if(isRunning()){
            stopControllerTunnel();
            if(controller != null){
                Properties cfg = loadConfig(configFile);
                controller.setConfig(cfg, "");
                restartControllerTunnel();
                org.klomp.snarkxl.SnarkManager.instance().addMessage("XLProxy configuration refreshed. Restarting");
            }
        }else if(controller != null){
            Properties cfg = loadConfig(configFile);
            controller.setConfig(cfg, "");
            org.klomp.snarkxl.SnarkManager.instance().addMessage("XLProxy configuration refreshed.");
        }
    }
}