package com.k_int.sru.search_widget;

import java.awt.Dimension;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.swing.JTextArea;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

import com.k_int.commons.util.XMLUtil;
import com.k_int.sru.search_widget.bean.ProxiedBeanFactory;
import com.k_int.sru.search_widget.bean.QueryStringBean;
import com.k_int.sru.search_widget.bean.ServiceBean;
import com.k_int.sru.search_widget.ui.WidgetQueryStrings;
import com.k_int.sru.search_widget.ui.WidgetServiceList;
import com.k_int.sru.search_widget.util.XMLHelper;
import com.k_int.sru.search_widget.auth.ProxyConfig;

public class WidgetConfig {
  private static final Log    log              = LogFactory.getLog(WidgetConfig.class);
  private static final String FILE_QUERY_STRS  = "QueryStrings.xml";
  private static final String FILE_SERVICES    = "Services.xml";
  private static final String FILE_PREFS       = "prefs.properties";
  private static final String PREF_SIZE_X      = "widget_size_x";
  private static final String PREF_SIZE_Y      = "widget_size_y";
  private static final String FILE_DIR         = "./serialized";
  public static final String ICON_NAME         = "remove.png";
  
  private ProxyConfig         proxy_config;
  private Properties          prefs;
  private WidgetQueryStrings  query_strings      = null;
  private WidgetServiceList   services           = null;
  private boolean             detailed_view      = true;
  private Class<?>            default_field_type = JTextArea.class;
  private Dimension           preferred_size;
  
  
  public WidgetConfig() { 
    services      = new WidgetServiceList();
    query_strings = new WidgetQueryStrings();
    proxy_config  = new ProxyConfig(false); 

    try {
      checkXMLFilesExist();
    } catch (IOException ioe) {
      ioe.printStackTrace();
      System.exit(1);
    }
    
    try {
      List<QueryStringBean> qs_list = XMLHelper.getApplicationSpecificQueryStrings(
        com.k_int.commons.util.XMLUtil.buildFromFile(FILE_DIR+"/"+FILE_QUERY_STRS)
      ); 

      if (qs_list==null || qs_list.size()==0) {
        qs_list = new ArrayList<QueryStringBean>();
        qs_list.add(new QueryStringBean("operation",      "searchRetrieve", true));
        qs_list.add(new QueryStringBean("startRecord",    "1", true));
        qs_list.add(new QueryStringBean("maximumRecords", "10", true));
        qs_list.add(new QueryStringBean("recordSchema",   "dc", true));
        qs_list.add(new QueryStringBean("version",        "1.1", true));
        saveQueryStrings(qs_list);
      }

      for (QueryStringBean qs : qs_list) {
        query_strings.add(qs);  
      }
             
      services.setList(
        XMLHelper.getServices(
          XMLUtil.buildFromFile(FILE_DIR+"/"+FILE_SERVICES), 
          new ProxiedBeanFactory()
        )
      );
  
    } catch (SAXException saxe) {
      saxe.printStackTrace();
    } catch (FileNotFoundException fe) {
      fe.printStackTrace();
    } catch (ParserConfigurationException pce) {
      pce.printStackTrace();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
    
    initPrefs();
  }
  
 
  public void setUseProxyServer(boolean use_proxy) {
    proxy_config = new ProxyConfig(use_proxy);
  }


  public void setProxyInfo(String host, String port, String username, String password, String domain) {
    proxy_config.setProxyInfo(host, port, username, password, domain);
  }

 
  /**
   * Saves a new set of {@link QueryStringDTO} to the XML file.
   * 
   * @param new_qs The {@link List} of {@link QueryStringBean} to be saved.
   */
  public void saveQueryStrings(List<QueryStringBean> new_qs) {
    Map<String, QueryStringBean> qs_to_save = new HashMap<String, QueryStringBean>();
    
    for (QueryStringBean bean : new_qs) {
      if (bean.getToDelete()==null || !bean.getToDelete()) {
        qs_to_save.put(bean.getKey(), bean);
      }
    }
    
    query_strings.setStrings(qs_to_save);
    
    
    try {
      XMLUtil.saveToFile(
        XMLHelper.buildFromQueryStrings(query_strings.getStrings()), 
        FILE_DIR+"/"+FILE_QUERY_STRS
      );
      
    } catch (ParserConfigurationException pce) {
      pce.printStackTrace();
    } catch (TransformerException te) {
      te.printStackTrace();
    } catch (FileNotFoundException fnfe) {
      fnfe.printStackTrace();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
  
  
  /**
   * Saves a new set of {@link ServiceDTO} to the XML file.
   * 
   * @param new_services The {@link List} of {@link ServiceDTO} to be saved.
   */
  public void saveServices(List<Object> new_services) {
    if (new_services!=null) {
      List<ServiceBean> services_to_save = new ArrayList<ServiceBean>();
    
      for (Object o : new_services) {
        ServiceBean bean = (ServiceBean) o;
        
        if (bean.getToDelete()==null || !bean.getToDelete()) {
          services_to_save.add(bean);
        }
      }
      
      services.setList(services_to_save);
      
    } else {
      services.fireUpdate();
    }
    
    log.info("Saving services to file");
    try {
      XMLUtil.saveToFile(
        XMLHelper.buildFromServiceList(services.getList()), 
        FILE_DIR+"/"+FILE_SERVICES
      );
      
    } catch (ParserConfigurationException pce) {
      pce.printStackTrace();
    } catch (TransformerException te) {
      te.printStackTrace();
    } catch (FileNotFoundException fnfe) {
      fnfe.printStackTrace();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
  
  
  private void initPrefs() {
    prefs          = new Properties();
    Dimension size = null;
    
    Integer default_x = 600;
    Integer default_y = 400;
    
    try {
      FileInputStream fis = new FileInputStream(FILE_DIR+"/"+FILE_PREFS);
      prefs.load(fis);
      fis.close();
      String pref_x = prefs.getProperty(PREF_SIZE_X);
      String pref_y = prefs.getProperty(PREF_SIZE_Y);
      
      Integer x = (pref_x==null ? default_x : Integer.parseInt(pref_x));
      Integer y = (pref_y==null ? default_y : Integer.parseInt(pref_y));
      
      size = new Dimension(x,y);
      
    } catch (IOException ioe) {
      size   = new Dimension(default_x, default_y);
      File f = new File(FILE_DIR+"/"+FILE_PREFS);
      try {
        f.createNewFile();
      } catch (IOException ioe2) {
        ioe2.printStackTrace();
        System.exit(1);
      }
    }
    
    preferred_size = size;
  }
  
  
  
  /**
   * Adds a new service to the persistent store and allows it to be searched.
   * 
   * @param service The newly created {@link ServiceBean}. 
   */
  public void addNewService(ServiceBean service) {
    if (service.getIsDefault()) {
      for (ServiceBean bean : services.getList()) {
        bean.setIsDefault(false);
      }
    }
    services.add(service);
  }
  
  
  /**
   * Adds a new query string to the persistent store.
   * 
   * @param qs The newly created {@link QueryStringDTO}.
   */
  public void addNewQueryString(QueryStringBean qs) {
    query_strings.add(qs);
  }
  
  
  /**
   * Searches the list of services stored in memory for the given name.
   * 
   * @param name The name of the service to locate.
   * @return The {@link String} representation of the {@link URL} of the located service.
   */
  public ServiceBean getServiceByName(String name) {
    ServiceBean service = null;
    
    for (ServiceBean s : services.getList()) {
      if (s.getName().equals(name)) {
        service = s;
      }
    }
    
    return service;
  }
  
  
  private void checkXMLFilesExist() throws IOException {
    File dir = new File(FILE_DIR);
    if (!dir.exists()) {
      dir.mkdir();
    }
    
    File qs_file = new File(FILE_DIR+"/"+FILE_QUERY_STRS);
    if (!qs_file.exists()) {
      BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_DIR+"/"+FILE_QUERY_STRS));
      bw.write("<?xml version=\"1.0\"?><sruQueryStrings></sruQueryStrings>");
      bw.close();
    }

    File s_file  = new File(FILE_DIR+"/"+FILE_SERVICES);
    if (!s_file.exists()) {
      BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_DIR+"/"+FILE_SERVICES));
      bw.write("<?xml version=\"1.0\"?><services xmlns:srw=\"http://www.loc.gov/zing/srw/\"></services>");
      bw.close();
    }
  }
  
  
  public void savePreferences(int x, int y) {
    prefs.setProperty(PREF_SIZE_X, x+"");
    prefs.setProperty(PREF_SIZE_Y, y+"");
    
    try {
      prefs.store(new FileOutputStream(FILE_DIR+"/"+FILE_PREFS), "Stored user preferences");
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
 
  public void setDetailedView(boolean detailed_view)       { this.detailed_view = detailed_view; }
  public Class<?> getDefaultFieldType()                    { return default_field_type;          } 
  public boolean getDetailedView()                         { return detailed_view;               }
  public WidgetQueryStrings           getQueryStrings()    { return query_strings;               }
  public ProxyConfig                  getProxyConfig()     { return proxy_config;                }
  public Map<String, QueryStringBean> getQueryStringsMap() { return query_strings.getStrings();  }
  public WidgetServiceList            getServices()        { return services;                    }
  public List<ServiceBean>            getServiceList()     { return services.getList();          }
  public Dimension                    getPreferredSize()   { return preferred_size;              } 
}
