/*=======================================================
 * CommandOptionList.java 
 *
 * "A Tcl like language implementation in Java named APWTCL
 * ((Java) Arnulf's Preferred Web Tcl)"
 *
 * APWTCL CommandOptionList class
 *
 * Released under same BSD license as Tcl.
 * (Tcl BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
 *
 * Copyright 2012 Arnulf P. Wiedemann
 *
 */

package org.apwtcl.lang;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

public class CommandOptionList extends Token implements Debug {
  private static int oid = 0;

  private int id;
  private Interp interp;

  public HashMap<String, CommandOption> option_list;  /* this list of valid options for this command */

  private int option_flags;
  private HashMap<String, ApwtclObj> option_values;
  private String err_msg;
  private int num_processed_args;
  private HashMap<Integer, String> opt_code2opt_name;


  /* ==================== CommandOptionList ================================== */
  public CommandOptionList(Interp interp) {
    oid++;
    id = oid;

    this.interp = interp;
    this.option_list = new HashMap<String, CommandOption>();
    this.opt_code2opt_name = new HashMap<Integer, String>();
  }

  /* ==================== mySelf ================================== */
  public String mySelf() {
    String str = "CommandOptionList!"+id+"!";
    return str;
  } 
      
  /* ==================== toString ===================================== */
  public String toString() {
    return mySelf()+"!";
  }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }

  /* ==================== addOption ===================================== */
  public void addOption(String option_name, int option_code, boolean has_opt_value, 
		  ArrayList<ApwtclObj> default_value, HashMap<String, Integer>allowed_option_values) {
    CommandOption option = new CommandOption(interp, option_name, option_code, has_opt_value, default_value, 
    		allowed_option_values);
    option_list.put(option_name, option);
    opt_code2opt_name.put(option_code, option_name);
  }

  /* ==================== hasOption ===================================== */
  public boolean hasOption(String option_name) {
    if (option_list.get(option_name) != null) {
      return true;
    }
    return false;
  }

  /* ==================== optionHasValue ===================================== */
  public boolean optionHasValue(String option_name) {
    CommandOption option = option_list.get(option_name);
    if (option == null) {
      return false;
    }
    return option.opt_has_value;
  }

  /* ==================== optionCode ===================================== */
  public int optionCode(String option_name) {
    CommandOption option = option_list.get(option_name);
    if (option == null) {
      return -1;
    }
    return option.opt_code;
  }

  /* ==================== getErrorMsg ===================================== */
  public String getErrorMsg() {
    return err_msg;
  }

  /* ==================== getOptionFlags ===================================== */
  public int getOptionFlags() {
    return option_flags;
  }

  /* ==================== getNumProcessedArgs ===================================== */
  public int getNumProcessedArgs() {
    return num_processed_args;
  }

  /* ==================== getOptionFlagNames ===================================== */
  public String getOptionFlagNames() {
    StringBuffer str = new StringBuffer();
    String sep = "";

    ArrayList<String> my_lst = new ArrayList<String>(option_list.keySet());
    Collections.sort(my_lst);
    for (String z: my_lst) {
      str.append(sep+z);
      sep = " ";
    }
    return str.toString();
  }

  /* ==================== getOptionFlagsList ===================================== */
  public ApwtclObj getOptionFlagsList() {
    ApwtclObj result_lst = interp.list_obj_type.newListObj(null, 0);

    ArrayList<String> my_lst = new ArrayList<String>(option_list.keySet());
    Collections.sort(my_lst);
    for (String z: my_lst) {
      interp.list_obj_type.listAppendElement(result_lst, interp.string_obj_type.newStringObj(z,-1, "COMMAND_OPTION_LIST_1"));
    }
    return result_lst;
  }

  /* ==================== getOptionValue ===================================== */
  public ArrayList<ApwtclObj> getOptionValue(int opt_code) {
    String opt_name = opt_code2opt_name.get(opt_code);
    if (opt_name == null) {
      return null;
    }
    ApwtclObj value = option_values.get(opt_name);
    if (value != null) {
      ArrayList<ApwtclObj> ll = new ArrayList<ApwtclObj>();
      ll.add(value);
      return ll;
    }
    CommandOption option = option_list.get(opt_name);
    return option.default_value;
  }

  /* ==================== getOptionValueFromName ===================================== */
  public ArrayList<ApwtclObj> getOptionValueFromName(String opt_name) {
    ApwtclObj value = option_values.get(opt_name);
    if (value != null) {
      ArrayList<ApwtclObj> ll = new ArrayList<ApwtclObj>();
      ll.add(value);
      return ll;
    }
    CommandOption option = option_list.get(opt_name);
    return option.default_value;
  }

  /* ==================== resetOptionValues ===================================== */
  public void resetOptionValues() {
    option_values = new HashMap<String, ApwtclObj>();
  }

  /* ==================== parseOptions ===================================== */
  public int parseOptions(ArrayList<ApwtclObj> args, int start_idx, String msg_start) {
    String option;

    num_processed_args = 0;
    option_flags = 0;
    err_msg = "";

    for (int i = start_idx; i < args.size(); i++) {
      option = args.get(i).getString();
//print("option!"+option+"!");
      if (option.charAt(0) != '-') {
        /* seems to be end of options */
        break;
      }
      if (option.equals("--")) {
        /* end of options */
        num_processed_args++;
        i++;
        break;
      }
      CommandOption option_info = option_list.get(option);
      if (option_info == null) {
        StringBuffer msg = new StringBuffer(msg_start+" bad option: '"+option+"' should be one of: '");
        String sep = "";
        for (String opt: option_list.keySet()) {
           msg.append(sep + opt);
           sep = ", ";
        }
        err_msg = msg.toString();
        return ERROR;
      }
      num_processed_args++;
      option_flags |= option_info.opt_code;
      if (optionHasValue(option)) {
        i++;
        if (i == args.size()) {
          err_msg = msg_start+" must be an even number of option name and option value";
          return ERROR;
        }
        num_processed_args++;
        if (option_info.allowed_option_values != null) {
          if (option_info.allowed_option_values.get(args.get(i).getString()) == null) {
            err_msg = msg_start+" bad value for option \""+option+"\" must be: "+option_info.getAllowedOptionValues();
            return ERROR;
	  }
	}
        option_values.put(option, args.get(i));
      }
    }
//print("num_processed_args!"+num_processed_args+"!");
    return OK;
  }

}
