package com.k_int.srusolr.action;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;


public class AdvancedSearchAction extends BaseSearchAction {
  private static final long serialVersionUID = 1L;
  private final String SRU_PARAM_SEPERATOR = " AND ";
  // names of parameter keys that will be used to build sru query
  private final String SRU_PARAM_SVC      = "ispp.svc";
  private final String SRU_PARAM_LOC      = "ispp.loc";
  private final String SRU_PARAM_AGE_MIN  = "ispp.minage";
  private final String SRU_PARAM_AGE_MAX  = "ispp.maxage";
  private final String SRU_PARAM_VAC      = "ispp.nextvac";
  private final String SRU_PARAM_REG      = "ispp.reg";
  private final String SRU_PARAM_FAC      = "ispp.fac";
  private final String SRU_PARAM_INSP     = "ispp.inpdate";
  private final String SRU_PARAM_FLAG     = "ispp.flags";
  private final String SRU_PARAM_POST     = "ispp.postcode";
  // names of input fields in form
  private String services;
  private String location;
  private String age;
  private String crb;
  private String immvac;
  private String reg;
  private String inspdate;
  private String facilities;
  private String provdiet;
  private String provcultural;
  private String provspecial;
  private String provwheel;
  private String postcode;
  // storage of validated parameters
  private Map<String, String> query_params = new HashMap<String, String>();
  
  // struts2 action-to-form map getters and setters  
  public void setServices(String services)         { this.services = services;         }
  public String getServices()                      { return services;                  }
  
  public void setLocation(String location)         { this.location = location;         }
  public String getLocation()                      { return location;                  }
  
  public void setAge(String age)                   { this.age = age;                   }
  public String getAge()                           { return age;                       }
  
  public void setCrb(String crb)                   { this.crb = crb;                   }
  public String getCrb()                           { return crb;                       }
  
  public void setImmvac(String immvac)             { this.immvac = immvac;             }
  public String getImmvac()                        { return immvac;                    }
  
  public void setProvdiet(String provdiet)         { this.provdiet = provdiet;         }
  public String getProvdiet()                      { return provdiet;                  }
    
  public void setProvcultural(String provcultural) { this.provcultural = provcultural; }
  public String getProvcultural()                  { return provcultural;              }

  public void setProvwheel(String provwheel)       { this.provwheel = provwheel;       }
  public String getProvwheel()                     { return provwheel;                 }

  public void setProvspecial(String provspecial)   { this.provspecial = provspecial;   }
  public String getProvspecial()                   { return provspecial;               }
  
  public void setReg(String reg)                   { this.reg = reg;                   }
  public String getReg()                           { return reg;                       }

  public void setFacilities(String facilities)     { this.facilities = facilities;     }
  public String getFacilities()                    { return facilities;                }

  public void setInspdate(String inspdate)         { this.inspdate = inspdate;         }
  public String getInspdate()                      { return inspdate;                  }
  
  public void setPostcode(String postcode)         { this.postcode = postcode;         }
  public String getPostcode()                      { return postcode;                  }
  
  /*
   * not yet used
    String within    = request.getParameter("miles");
    String min_cost  = request.getParameter("mincost");
    String max_cost  = request.getParameter("maxcost");
   */
    
  
  
  public String internalExecute() throws Exception {
    String result = SUCCESS;
    
    // add input fields to map if present
    addOrDropText(SRU_PARAM_SVC,     services);
    addOrDropText(SRU_PARAM_LOC,     location);
    addOrDropText(SRU_PARAM_AGE_MIN, age);
    addOrDropText(SRU_PARAM_AGE_MAX, age);
    addOrDropText(SRU_PARAM_REG,     reg);
    addOrDropText(SRU_PARAM_FAC,     facilities);
    addOrDropText(SRU_PARAM_INSP,    inspdate);
    addOrDropText(SRU_PARAM_POST,    postcode);
    // add checkboxes to flags map entry
    addOrDropFlag(crb,          "crb");
    addOrDropFlag(provdiet,     "diet");
    addOrDropFlag(provcultural, "cultural");
    addOrDropFlag(provwheel,    "wheel");
    addOrDropFlag(provspecial,  "special");

    SimpleDateFormat input_format = new SimpleDateFormat("dd-MM-yyyy");
    SimpleDateFormat solr_format  = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    
    // add current date to parameter map if immediate vacancy is checked.
    if (immvac!=null && immvac.equals("true")) {
      query_params.put(SRU_PARAM_VAC, solr_format.format(new Date()));
    }
    
    // validate age entry - must be valid integer - just check min as min & max should match
    if (query_params.get(SRU_PARAM_AGE_MIN)!=null) {
      try {
        Integer.parseInt(query_params.get(SRU_PARAM_AGE_MIN));
      } catch (NumberFormatException nfe) {
        result = ERROR;
        addFieldError("age", "The age given is not valid, please enter a whole number.");
      }
    } 

    // validate date of last inspection entry - must be valid & formatted date in input by date picker 
    if (query_params.get(SRU_PARAM_INSP)!=null) {
      try {
        Date d = input_format.parse(query_params.get(SRU_PARAM_INSP));
        query_params.put(SRU_PARAM_INSP, solr_format.format(d));

      } catch (ParseException pe) {
        result = ERROR;
        addFieldError("inspdate", "The date given is not valid, please use the date picker.");
      }
    }

    // assuming no errors, build up the query string
    if (!result.equals(ERROR)) {
      if (query_params.size()>0) {
        StringBuilder sb = new StringBuilder("");
        Iterator<Entry<String, String>> param_it = query_params.entrySet().iterator();
        while (param_it.hasNext()) {
          Entry<String, String> param = param_it.next();
          sb.append(param.getKey());
          String op;
          
          if (param.getKey().equals(SRU_PARAM_AGE_MAX)) {
            op = "<=";
          } else if (param.getKey().equals(SRU_PARAM_AGE_MIN)) {
            op = ">=";
          } else {
            op = "=";
          }
          
          sb.append(op);
          if (param.getKey().equals(SRU_PARAM_FLAG)) {
            sb.append("(");
            sb.append(param.getValue());
            sb.append(")");
          } else {
            if (!param.getValue().startsWith("\"")) sb.append("\"");
            sb.append(param.getValue());
            if (!param.getValue().endsWith("\"")) sb.append("\"");
          }
        
          if (param_it.hasNext()) sb.append(SRU_PARAM_SEPERATOR); 
        }
      
        query = sb.toString();
        
      } else {
        result = ERROR;
      }
    }

    return result;
  }
  
  
  private void addOrDropText(String key, String value) {
    if (value!=null && !value.trim().equals("")) {
      query_params.put(key, value);
    }    
  }
  
  
  private void addOrDropFlag(String flag_param, String flag_value) {
    if (flag_param!=null && flag_param.equals("true")) {
      if (query_params.get(SRU_PARAM_FLAG)==null) {
        query_params.put(SRU_PARAM_FLAG, flag_value);
      } else {
        query_params.put(SRU_PARAM_FLAG, query_params.get(SRU_PARAM_FLAG)+SRU_PARAM_SEPERATOR+flag_value);
      }
    }
  }
}