package utils;
import java.awt.event.KeyEvent;
import java.io.*;
import java.util.Properties;
import uk.ac.ic.doc.automed.*;
import uk.ac.ic.doc.automed.reps.*;
import uk.ac.ic.doc.automed.wrappers.*;
import org.apache.commons.cli.*;

/*
 * A few methods used by the AutoMed example applications.
 */
public class AutoMedUtils {
  public static int debug = 0;
  
  public static boolean checkAndIntegrateSchemas(Schema s1, Schema s2) {
    SchemaObject[] aLessB = s1.differenceByName(s2);
    SchemaObject[] bLessA = s2.differenceByName(s1);
    boolean integrationOK = true;
    
    if (aLessB.length > 0) {
      System.out.println(s1.getName() + "-" + s2.getName() + "=");
      for (int i = 0; i < aLessB.length; i++)
        System.out.println("  " + aLessB[i]);
      integrationOK = false;
    }
    
    if (bLessA.length > 0) {
      System.out.println(s2.getName() + "-" + s1.getName() + "=");
      for (int i = 0; i < bLessA.length; i++)
        System.out.println("  " + bLessA[i]);
      integrationOK = false;
    }
    
    if (integrationOK) {
      try {
        Transformation.createIdentTransformation(s1, s2, null, null);
        System.out.println("Integration of " + s1.getName() + " and " + s2.getName() + " succeeded");
      } catch (SchemasNotIdenticalException e) {
        throw new InconsistentException("Ident of identical schemas failed", e);
      }
      
      return true;
    }
    
    return false;
  }
  
  // Start Lucas 30/06/06
  // Overload method to accept id flavour
  
  /**
   * This should be a fairly standard check in an AutoMed application to see if two schemas can be "integrated" via an ID
   * transformation.
   *
   * @throws AutoMedException
   */
  public static void integrateSchemas(Schema s1, Schema s2, String iqlFunction) throws AutoMedException {
    if (!iqlFunction.equals("choose") && !iqlFunction.equals("setUnion") && !iqlFunction.equals("(++)")
    && !iqlFunction.equals("intersect"))
      throw new AutoMedException("Incorrect IQL function used for id transformation: " + iqlFunction);
    
    boolean integrationOK = true;
    
    System.out.print("Integration of " + s1.getName() + " and " + s2.getName());
    
    try {
      Transformation t = Transformation.createIdentTransformation(s1, s2, null, null);
      t.setProperty(Transformation.PROPERTY_IQL_FUNCTION, iqlFunction);
      System.out.println(" succeeded");
    } catch (SchemasNotIdenticalException e) {
      System.out.println(" failed");
      
      System.out.print("*** Schema " + e.getFromSchema().getName());
      System.out.println("has following SchemaObjects not matched");
      SchemaObject[] fromSo = e.getFromObjectsUnmatched();
      for (int i = 0; i < fromSo.length; i++)
        System.out.println(fromSo[i]);
      
      System.out.print("*** Schema " + e.getToSchema().getName());
      System.out.println("has following SchemaObjects not matched");
      SchemaObject[] toSo = e.getToObjectsUnmatched();
      for (int i = 0; i < toSo.length; i++)
        System.out.println(toSo[i]);
    }
  }
  
  public static void integrateSchemas(Schema s1, Schema s2) throws AutoMedException {
    integrateSchemas(s1, s2, Transformation.PROPERTY_IQL_FUNCTION_DEFAULT_VALUE);
  }
  
  // End Lucas 30/06/06
  
  public static void banner(String title) {
    int len = title.length();
    String stars = "**********************************************" + "*********************************";
    int slen = stars.length();
    
    System.out.println(stars);
    if (len > slen - 4)
      System.out.println(title);
    else
      System.out.println(stars.substring(0, (slen - len) / 2 - 1) + " " + title + (len % 2 == 0 ? " " : "  ")
      + stars.substring(0, (slen - len) / 2));
    System.out.println(stars);
  }
  
  public static void banner(Schema s) {
    banner(s.getName());
  }
  
  private static boolean bombOut = false;
  
  public static Schema wrapSchema(String username, String password, String driver, String urlbase, SQLWrapperFactory wf,
    String db, String name) throws Exception {
    // Ensure we are clear of all the schemas we are to create
    String sourceName = name + "_src";
    if (Schema.exists(name))
      Schema.getSchema(name).retract();
    if (Schema.exists(sourceName))
      Schema.getSchema(sourceName).retract();
    
    // Get the Source oriented schema
    AutoMedWrapper sw = AutoMedWrapper
      .selectNewAutoMedWrapper(username, password, null, driver, urlbase + db, sourceName, wf);
    Schema sourceSchema = sw.getSchema();
    banner(sourceSchema);
    sourceSchema.listSchema();
    
    // Generate an AutoMed oriented schema
    Schema s = sw.newAutoMedSchema(name);
    banner(s);
    s.listSchema();
    
    return s;
  }
  
  // dmle 23/5/2006
  /**
   * Prompt user for Yes/No dialog
   *
   * @param defaultChoice
   *            1 for 'Y', 0 for 'N' (or anythingelse)
   * @return int 1 for 'Y', 0 for 'N' (or anythingelse)
   */
  public static int dialogYesNo(String prompt, long defaultChoice) {
    
    String defaultChar = (defaultChoice == 1) ? "Y" : "N";
    System.out
      .print("\n\n"
      + prompt
      + ((prompt.trim().endsWith("?")) ? " (Y)es/(N)o, [" + defaultChar + "] " : "? (Y)es/(N)o, ["
      + defaultChar + "] "));
    
    // open up standard input
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    try {
      // String response = br.readLine();
      int charResponse = br.read();
      
      if ((((byte) charResponse) == ((byte) KeyEvent.VK_ENTER))) {
        return (int) defaultChoice;
      } else {
        if (charResponse == 'Y' || charResponse == 'y') {
          return 1;
        } else {
          return 0;
        }
      }
    } catch (IOException ioe) {
      System.out.println("Error reading user input, will assume 'No'");
      return 0;
    }
  }
  
  // dmle 09/08/2006
  /**
   * Display a list of items, number each item so that user can choose. A default
   * choice is given to the first item
   *
   */
  public static int displayItemList(String[] items) {
    StringBuffer sb = new StringBuffer();
    sb.append("Select from the following list:").append("\n");
    for (int i = 0 ; i < items.length; i++) {
      sb.append((i+1)+") " + items[i]).append("\n");
    }
    sb.append("\n");
    sb.append("\tYour choice:");
    
    System.out.println(sb.toString());
    
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    int choice = 1;
    try {
      choice = Integer.parseInt(br.readLine());
    } catch (IOException ioe) {
      System.out.println("Error reading user input, will assume 'No'");
      return 0;
    } catch (NumberFormatException nfe) {
      System.out.println("Invalid selection, assume the first one!");
    }
    
    return --choice;
  }
  
  public static String getCmdLineInput(String prompt) {
    System.out.print(prompt);
    
    String resp = "null";
    
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    try {
      resp = br.readLine();
      if (resp.equals("\n") || resp.trim().equals("")) {
        resp = "null";
      }      
    } catch (IOException ioe) {
      System.out.println("Error reading user input");      
    }
    
    return resp;
    
  }
  
  /**
   * Print out cmd usage for pre-configured command options
   */
  public static void printCmdUsage(String desc, Options opts) {
    HelpFormatter hf = new HelpFormatter();
    hf.printHelp(desc, opts, true);
  }
  
  /**
   * Read in a scenario configuration file to return the actions
   */
  public static int[] readScenarioFile(String filePath, Class byClass) throws
  AutoMedException {
    Properties props = new Properties();
    int[] items;
    try {
      props.load(byClass.getResourceAsStream(filePath));
      String actionStr = props.getProperty("actions");
      String[] actions = uk.ac.ic.doc.automed.Util.split(actionStr, ",");
      items = new int[actions.length];
      for (int i = 0; i < actions.length; i++) {
        items[i] = Integer.parseInt(actions[i]);
      }
    } catch (Exception ex) {
      throw new AutoMedException("Failed to read scenario file " + filePath + " by class " + byClass.getName(), ex);
    }
    
    return items;
  }
}
