package brn.sim;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Vector;

import brn.sim.DataManager.DataContribution;
import brn.sim.builder.Builder;
import brn.sim.builder.FieldBuilder;
import brn.sim.builder.MacBuilder;
import brn.sim.builder.NetBuilder;
import brn.sim.builder.NodeBuilder;
import brn.sim.builder.PathLossBuilder;
import brn.sim.builder.RadioBuilder;
import brn.sim.builder.RouteBuilder;
import brn.sim.builder.Builder.Params;
import brn.sim.builder.NodeBuilder.NodeParams;

import jist.runtime.JistAPI;
import jist.runtime.Main;
import jist.swans.Constants;
import jist.swans.misc.Util;

public class AbstractParams extends Builder.Params implements JistAPI.DoNotRewrite, Cloneable, Serializable, DataContribution {

  private static final long serialVersionUID = 1L;

  // ////////////////////////////////////////////////
  // external connectors
  //

  /** look for gui on local host */
  public boolean gui = true;
  /** host where the gui runs */
  public String uiHost = "localhost";
  /** port on which the gui listens */
  public int uiPort = Main.JIST_PORT;

  /** whether to connect to the specified db */
  public boolean db = false;
  /** url of the definitions data base to use */
  public String dbDef = "jdbc:mysql://localhost:3306/simulation";
  /** url of the results data base to use */
  public String dbRes = "jdbc:mysql://localhost:3306/simulation";
  /** database user */
  public String dbUser = "distsim";
  /** password of the database user */
  public String dbPassword = "distsim";
  /** job id to set in db, for later identification of the job */
  public int dbJobId = 0;

  /** whether to store the data in files */
  public boolean file = false;
  /** whether to store the data in binary files */
  public boolean fileBinary = false;
  /** if not db, use the given directory for storage */
  public String directory = "";


  // ////////////////////////////////////////////////
  // active handlers
  //

  /** sample legth for all handlers in sec */
  public double sampleLen = .5;

  /** amount of information to collect at the field layer (node movement) */
  public int handlerFieldLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at the radio layer */
  public int handlerRadioLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect diversity information at radio layer () */
  public int handlerRadioDivLevel = DataManager.LEVEL_OFF;
  /** time bars for radio events */
  public int handlerRadioTimeBarLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at the mac layer*/
  public int handlerMacLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at TXOP */
  public int handlerTXOPLevel = DataManager.LEVEL_OFF;
  /** time bars for mac events */
  public int handlerMacTimeBarLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at the mac layer in rate module*/
  public int handlerRateLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at the net layer*/
  public int handlerNetLevel = DataManager.LEVEL_OFF;
  /** time bars for net events */
  public int handlerNetTimeBarLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at the route layer*/
  public int handlerRouteLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect at the trans layer*/
  public int handlerTransLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect per flow */
  public int handlerFlowLevel = DataManager.LEVEL_OFF;
  /** generate forward graph */
  public int handlerForwardGraphLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect from the link tables */
  public int handlerLinkTableLevel = DataManager.LEVEL_OFF;
  /** amount of information to collect about link quality and snr */
  public int handlerLinkQualityLevel = DataManager.LEVEL_OFF;

  /** @deprecated collect information on field layer (node movement) */
  public boolean handlerField = false;
  /** @deprecated collect information on radio layer */
  public boolean handlerRadio = false;
  /** @deprecated collect extended information on radio layer */
  public boolean handlerRadioEx = false;
  /** @deprecated time bars for radio events */
  public boolean handlerRadioTimeBar = false;
  /** @deprecated collect information on mac layer*/
  public boolean handlerMac = false;
  /** @deprecated time bars for mac events */
  public boolean handlerMacTimeBar = false;
  /** @deprecated collect information on mac layer in rate module*/
  public boolean handlerRate = false;
  /** @deprecated collect information on net layer*/
  public boolean handlerNet = false;
  /** @deprecated time bars for net events */
  public boolean handlerNetTimeBar = false;
  /** @deprecated collect information on route layer*/
  public boolean handlerRoute = false;
  /** @deprecated collect information on trans layer*/
  public boolean handlerTrans = false;
  /** @deprecated collect information per flow */
  public boolean handlerFlow = false;
  /** @deprecated generate forward graph */
  public boolean handlerForwardGraph = false;
  /** @deprecated collect link table information */
  public boolean handlerLinkTable = false;
  /** @deprecated collect link quality and snr information */
  public boolean handlerLinkQuality = false;
  /** @deprecated collect TXOP information */
  public boolean handlerTXOP = false;

  /** name of the field nam output file */
  public String dumpFieldNam = null;
  /** name of the net nam output file */
  public String dumpNetNam = null;
  /** name of the mac nam output file */
  public String dumpMacNam = null;
  /** name of the radio nam output file */
  public String dumpRadioNam = null;
  /** name of the GANTT mac mode output file */
  public String dumpMacGantt = null;

  /** dump mac packets */
  public boolean dumpMac = false;
  /** dump net packets */
  public boolean dumpNet = false;
  /** output file for radio traces */
  public String dumpRadio = null;

  /** name of the GANTT radio channel output file */
  public String dumpRadioChannelGantt = null;
  /** name of the GANTT radio mode output file */
  public String dumpRadioModeGantt = null;


  // ////////////////////////////////////////////////
  // simulation duration settings
  //

  /** Time to end simulation (in SEC) */
  public int endTime = 1000;
  /** Random seed. 0 leads to different seed each time simulation runs. */
  public int seed = 1;
  /** process asserts */
  public boolean assertion = true;


  // ////////////////////////////////////////////////
  // node settings
  //

  /**
   *  Number of nodes.
   *  @deprecated use {@link #nodeNumber}
   */
  public int nodes = 0;
  
  /** Start index of first node */
  public int nodesStart = 1;

  /** field parameter block */
  public Builder.Params field = new FieldBuilder.FieldParams();
  /** node parameter block
   * @deprecated use {@link #nodeParams}
   */
  public NodeBuilder.NodeParams node = new NodeBuilder.NodeParams();

  /** No. nodes to construct per node type */
  public int[] nodeNumber = new int[] { 0 };
  /** array of node types to construct */
  public NodeBuilder.NodeParams[] nodeParams = new NodeBuilder.NodeParams[] {new NodeBuilder.NodeParams()}; 



  // ////////////////////////////////////////////////
  // Implementation
  //

  public static void main(String[] args) throws Exception {
    AbstractParams params = new AbstractParams();

    // set parameters
    params.seed = 0;
    params.nodes = 21;
    params.assertion = true;

    FieldBuilder.FieldParams field = new FieldBuilder.FieldParams();
    field.fieldX = 2000;
    field.fieldY = 100;
    field.pathloss = new PathLossBuilder.ShadowingParams();
//    field.exponent = 2.7;
//    field.stdDeviation = 0.;
    field.spatial_mode = Constants.SPATIAL_LINEAR;
    params.field = field;

    RadioBuilder.NoiseParams radio = new RadioBuilder.NoiseAdditiveParams();
    radio.fieldX = field.fieldX;
    radio.fieldY = field.fieldY;
    radio.placement = Constants.PLACEMENT_GRID;
    radio.placementOpts = "21x1";
    radio.useAnnos = true;
    params.node.radio = radio;

    MacBuilder.M802_11Params mac = new MacBuilder.M802_11Params();
    mac.useAnnos = radio.useAnnos;
    mac.useBitRateAnnos = true;
    params.node.mac = mac;

    NetBuilder.IpParams net = new NetBuilder.IpParams();
    net.protocolMapper = new int[] { Constants.NET_PROTOCOL_UDP,
        Constants.NET_PROTOCOL_AODV };
    params.node.net = net;

    RouteBuilder.AodvParams route = new RouteBuilder.AodvParams();
    params.node.route = route;

    // and out
    Util.writeObject("res/config/AbstractParams.xml", params);
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.DataManager.DataContribution#getPath()
   */
  public String[] getPath() {
    return new String[] {"Global", "Config" };
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.DataManager.DataContribution#getType()
   */
  public int getType() {
    return DriverRemote.ITEM_TYPE_CONFIG;
  }
  
  /*
   * (non-Javadoc)
   * @see brn.sim.DataManager.DataContribution#setActive(boolean)
   */
  public void setActive(boolean active) {
  }

  public String getContent() throws Exception {
    BeanInfo info = Introspector.getBeanInfo(this.getClass());
    //    BeanDescriptor descr = info.getBeanDescriptor();
    PropertyDescriptor[] props = info.getPropertyDescriptors();

    Vector vec = new Vector(props.length);
    for (int k = 0; k < props.length; k++) {
      String name = props[k].getDisplayName();

      if (name.equals("path") || name.equals("type") || name.equals("content"))
        continue;

      boolean added = false;
      for (int i = 0; i < vec.size(); i++) {
        String str = ((PropertyDescriptor) vec.elementAt(i)).getDisplayName();
        if (name.compareToIgnoreCase(str) < 0) {
          vec.insertElementAt(props[k], i);
          added = true;
          break;
        }
      }
      if (!added)
        vec.addElement(props[k]);
    }

    String[][] m_properties = new String[vec.size()][2];
    for (int k = 0; k < vec.size(); k++) {
      PropertyDescriptor prop = (PropertyDescriptor) vec.elementAt(k);
      m_properties[k][0] = prop.getDisplayName();

      Method mRead = prop.getReadMethod();
      if (mRead != null && mRead.getParameterTypes().length == 0) {
        Object value = mRead.invoke(this, (Object[]) null);
        m_properties[k][1] = (null == value ? "null" : value.toString());
      } else
        m_properties[k][1] = "error";
    }

    StringBuilder builder = new StringBuilder();
    for (int k = 0; k < vec.size(); k++) {
      builder.append(m_properties[k][0]);
      builder.append("=");
      builder.append(m_properties[k][1]);
      builder.append("\n");
    }

    return builder.toString();
  }

  public boolean isAssertion() {
    return assertion;
  }

  public void setAssertion(boolean assertion) {
    this.assertion = assertion;
  }

  public boolean isDb() {
    return db;
  }

  public void setDb(boolean db) {
    this.db = db;
  }

  public String getDbDef() {
    return dbDef;
  }

  public void setDbDef(String dbDef) {
    this.dbDef = dbDef;
  }

  public int getDbJobId() {
    return dbJobId;
  }

  public void setDbJobId(int dbJobId) {
    this.dbJobId = dbJobId;
  }

  public String getDbPassword() {
    return dbPassword;
  }

  public void setDbPassword(String dbPassword) {
    this.dbPassword = dbPassword;
  }

  public String getDbRes() {
    return dbRes;
  }

  public void setDbRes(String dbRes) {
    this.dbRes = dbRes;
  }

  public String getDbUser() {
    return dbUser;
  }

  public void setDbUser(String dbUser) {
    this.dbUser = dbUser;
  }

  public String getDirectory() {
    return directory;
  }

  public void setDirectory(String directory) {
    this.directory = directory;
  }

  public String getDumpFieldNam() {
    return dumpFieldNam;
  }

  public void setDumpFieldNam(String dumpFieldNam) {
    this.dumpFieldNam = dumpFieldNam;
  }

  public boolean isDumpMac() {
    return dumpMac;
  }

  public void setDumpMac(boolean dumpMac) {
    this.dumpMac = dumpMac;
  }

  public String getDumpMacGantt() {
    return dumpMacGantt;
  }

  public void setDumpMacGantt(String dumpMacGantt) {
    this.dumpMacGantt = dumpMacGantt;
  }

  public String getDumpMacNam() {
    return dumpMacNam;
  }

  public void setDumpMacNam(String dumpMacNam) {
    this.dumpMacNam = dumpMacNam;
  }

  public boolean isDumpNet() {
    return dumpNet;
  }

  public void setDumpNet(boolean dumpNet) {
    this.dumpNet = dumpNet;
  }

  public String getDumpNetNam() {
    return dumpNetNam;
  }

  public void setDumpNetNam(String dumpNetNam) {
    this.dumpNetNam = dumpNetNam;
  }

  public String getDumpRadio() {
    return dumpRadio;
  }

  public void setDumpRadio(String dumpRadio) {
    this.dumpRadio = dumpRadio;
  }

  public String getDumpRadioNam() {
    return dumpRadioNam;
  }

  public void setDumpRadioNam(String dumpRadioNam) {
    this.dumpRadioNam = dumpRadioNam;
  }

  public int getEndTime() {
    return endTime;
  }

  public void setEndTime(int endTime) {
    this.endTime = endTime;
  }

  public boolean isFile() {
    return file;
  }

  public void setFile(boolean file) {
    this.file = file;
  }

  public boolean isGui() {
    return gui;
  }

  public void setGui(boolean gui) {
    this.gui = gui;
  }

  public boolean isHandlerField() {
    return handlerField;
  }

  public void setHandlerField(boolean handlerField) {
    this.handlerField = handlerField;
  }

  public boolean isHandlerFlow() {
    return handlerFlow;
  }

  public void setHandlerFlow(boolean handlerFlow) {
    this.handlerFlow = handlerFlow;
  }

  public boolean isHandlerForwardGraph() {
    return handlerForwardGraph;
  }

  public void setHandlerForwardGraph(boolean handlerForwardGraph) {
    this.handlerForwardGraph = handlerForwardGraph;
  }

  public boolean isHandlerLinkQuality() {
    return handlerLinkQuality;
  }

  public void setHandlerLinkQuality(boolean handlerLinkQuality) {
    this.handlerLinkQuality = handlerLinkQuality;
  }

  public boolean isHandlerLinkTable() {
    return handlerLinkTable;
  }

  public void setHandlerLinkTable(boolean handlerLinkTable) {
    this.handlerLinkTable = handlerLinkTable;
  }

  public boolean isHandlerMac() {
    return handlerMac;
  }

  public void setHandlerMac(boolean handlerMac) {
    this.handlerMac = handlerMac;
  }

  public boolean isHandlerNet() {
    return handlerNet;
  }

  public void setHandlerNet(boolean handlerNet) {
    this.handlerNet = handlerNet;
  }

  public boolean isHandlerRadio() {
    return handlerRadio;
  }

  public void setHandlerRadio(boolean handlerRadio) {
    this.handlerRadio = handlerRadio;
  }

  public boolean isHandlerRoute() {
    return handlerRoute;
  }

  public void setHandlerRoute(boolean handlerRoute) {
    this.handlerRoute = handlerRoute;
  }

  public int getNodes() {
    return nodes;
  }

  public void setNodes(int nodes) {
    this.nodes = nodes;
  }

  public int getSeed() {
    return seed;
  }

  public void setSeed(int seed) {
    this.seed = seed;
  }

  public String getUiHost() {
    return uiHost;
  }

  public void setUiHost(String uiHost) {
    this.uiHost = uiHost;
  }

  public int getUiPort() {
    return uiPort;
  }

  public void setUiPort(int uiPort) {
    this.uiPort = uiPort;
  }

  public NodeBuilder.NodeParams getNode() {
    return node;
  }

  public void setNode(NodeBuilder.NodeParams nodeParams) {
    this.node = nodeParams;
  }

  public Builder.Params getField() {
    return field;
  }

  public void setField(Builder.Params field) {
    this.field = field;
  }

  public boolean isHandlerRadioEx() {
    return handlerRadioEx;
  }

  public void setHandlerRadioEx(boolean handlerRadioEx) {
    this.handlerRadioEx = handlerRadioEx;
  }

  public boolean isHandlerMacTimeBar() {
    return handlerMacTimeBar;
  }

  public void setHandlerMacTimeBar(boolean handlerMacTimeBar) {
    this.handlerMacTimeBar = handlerMacTimeBar;
  }

  public boolean isHandlerNetTimeBar() {
    return handlerNetTimeBar;
  }

  public void setHandlerNetTimeBar(boolean handlerNetTimeBar) {
    this.handlerNetTimeBar = handlerNetTimeBar;
  }

  public boolean isHandlerRadioTimeBar() {
    return handlerRadioTimeBar;
  }

  public void setHandlerRadioTimeBar(boolean handlerRadioTimeBar) {
    this.handlerRadioTimeBar = handlerRadioTimeBar;
  }

  public String getDumpRadioChannelGantt() {
    return dumpRadioChannelGantt;
  }

  public void setDumpRadioChannelGantt(String dumpRadioChannelGantt) {
    this.dumpRadioChannelGantt = dumpRadioChannelGantt;
  }

  public String getDumpRadioModeGantt() {
    return dumpRadioModeGantt;
  }

  public void setDumpRadioModeGantt(String dumpRadioModeGantt) {
    this.dumpRadioModeGantt = dumpRadioModeGantt;
  }

  public boolean isFileBinary() {
    return fileBinary;
  }

  public void setFileBinary(boolean fileBinary) {
    this.fileBinary = fileBinary;
  }

  public double getSampleLen() {
    return sampleLen;
  }

  public void setSampleLen(double sampleLen) {
    this.sampleLen = sampleLen;
  }

  public boolean isHandlerTrans() {
    return handlerTrans;
  }

  public void setHandlerTrans(boolean handlerTrans) {
    this.handlerTrans = handlerTrans;
  }

  public boolean isHandlerTXOP() {
    return handlerTXOP;
  }

  public void setHandlerTXOP(boolean handlerTXOP) {
    this.handlerTXOP = handlerTXOP;
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.builder.Builder.Params#clone()
   */
  public Object clone() throws CloneNotSupportedException {
    AbstractParams ret = (AbstractParams) super.clone();
    //    uiHost = (String) uiHost.clone();
    //    dbDef = dbDef.clone();
    //    dbRes = dbRes.clone();
    //    dbUser = dbUser.clone();
    //    dbPassword = dbPassword.clone();
    //    directory = directory.clone();
    //    dumpFieldNam = dumpFieldNam.clone();
    //    dumpNetNam = dumpNetNam.clone();
    //    dumpMacNam = dumpMacNam.clone();
    //    dumpRadioNam = dumpRadioNam.clone();
    //    dumpMacGantt = dumpMacGantt.clone();
    //    dumpRadio = dumpRadio.clone();
    //    dumpRadioChannelGantt = dumpRadioChannelGantt.clone();
    //    dumpRadioModeGantt = dumpRadioModeGantt.clone();
    if (null != node)
      ret.node = (NodeParams) node.clone();
    if (null != field)
      ret.field = (Params) field.clone();
    if (null != nodeParams) {
      ret.nodeParams = (NodeParams[]) nodeParams.clone();
      for (int i = 0; i < ret.nodeParams.length; i++)
        ret.nodeParams[i] = (NodeParams) ret.nodeParams[i].clone();
    }
    return ret;
  }

  public int getNodesStart() {
    return nodesStart;
  }

  public void setNodesStart(int nodesStart) {
    this.nodesStart = nodesStart;
  }

  public boolean isHandlerRate() {
    return handlerRate;
  }

  public void setHandlerRate(boolean handlerRate) {
    this.handlerRate = handlerRate;
  }

  public int[] getNodeNumber() {
    return nodeNumber;
  }

  public void setNodeNumber(int[] nodeNumber) {
    this.nodeNumber = nodeNumber;
  }

  public NodeBuilder.NodeParams[] getNodeParams() {
    return nodeParams;
  }

  public void setNodeParams(NodeBuilder.NodeParams[] nodeParams) {
    this.nodeParams = nodeParams;
  }

  public int getHandlerRadioLevel() {
    return handlerRadioLevel;
  }

  public void setHandlerRadioLevel(int handlerRadioLevel) {
    this.handlerRadioLevel = handlerRadioLevel;
  }

  public int getHandlerFieldLevel() {
    return handlerFieldLevel;
  }

  public void setHandlerFieldLevel(int handlerFieldLevel) {
    this.handlerFieldLevel = handlerFieldLevel;
  }

  public int getHandlerRadioTimeBarLevel() {
    return handlerRadioTimeBarLevel;
  }

  public void setHandlerRadioTimeBarLevel(int handlerRadioTimeBarLevel) {
    this.handlerRadioTimeBarLevel = handlerRadioTimeBarLevel;
  }

  public int getHandlerMacLevel() {
    return handlerMacLevel;
  }

  public void setHandlerMacLevel(int handlerMacLevel) {
    this.handlerMacLevel = handlerMacLevel;
  }

  public int getHandlerTXOPLevel() {
    return handlerTXOPLevel;
  }

  public void setHandlerTXOPLevel(int handlerTXOPLevel) {
    this.handlerTXOPLevel = handlerTXOPLevel;
  }

  public int getHandlerMacTimeBarLevel() {
    return handlerMacTimeBarLevel;
  }

  public void setHandlerMacTimeBarLevel(int handlerMacTimeBarLevel) {
    this.handlerMacTimeBarLevel = handlerMacTimeBarLevel;
  }

  public int getHandlerRateLevel() {
    return handlerRateLevel;
  }

  public void setHandlerRateLevel(int handlerRateLevel) {
    this.handlerRateLevel = handlerRateLevel;
  }

  public int getHandlerNetLevel() {
    return handlerNetLevel;
  }

  public void setHandlerNetLevel(int handlerNetLevel) {
    this.handlerNetLevel = handlerNetLevel;
  }

  public int getHandlerNetTimeBarLevel() {
    return handlerNetTimeBarLevel;
  }

  public void setHandlerNetTimeBarLevel(int handlerNetTimeBarLevel) {
    this.handlerNetTimeBarLevel = handlerNetTimeBarLevel;
  }

  public int getHandlerRouteLevel() {
    return handlerRouteLevel;
  }

  public void setHandlerRouteLevel(int handlerRouteLevel) {
    this.handlerRouteLevel = handlerRouteLevel;
  }

  public int getHandlerTransLevel() {
    return handlerTransLevel;
  }

  public void setHandlerTransLevel(int handlerTransLevel) {
    this.handlerTransLevel = handlerTransLevel;
  }

  public int getHandlerFlowLevel() {
    return handlerFlowLevel;
  }

  public void setHandlerFlowLevel(int handlerFlowLevel) {
    this.handlerFlowLevel = handlerFlowLevel;
  }

  public int getHandlerForwardGraphLevel() {
    return handlerForwardGraphLevel;
  }

  public void setHandlerForwardGraphLevel(int handlerForwardGraphLevel) {
    this.handlerForwardGraphLevel = handlerForwardGraphLevel;
  }

  public int getHandlerLinkTableLevel() {
    return handlerLinkTableLevel;
  }

  public void setHandlerLinkTableLevel(int handlerLinkTableLevel) {
    this.handlerLinkTableLevel = handlerLinkTableLevel;
  }

  public int getHandlerLinkQualityLevel() {
    return handlerLinkQualityLevel;
  }

  public void setHandlerLinkQualityLevel(int handlerLinkQualityLevel) {
    this.handlerLinkQualityLevel = handlerLinkQualityLevel;
  }

  public int getHandlerRadioDivLevel() {
    return handlerRadioDivLevel;
  }

  public void setHandlerRadioDivLevel(int handlerRadioDivLevel) {
    this.handlerRadioDivLevel = handlerRadioDivLevel;
  }

}
