// Lightstreamer Portfolio Demo
// Table Management

//////////////// Portfolio Table Management

// the current portfolio should be chosen by the user according to the user profile;
// in this sample, user authentication is not included and a single portfolio is
// shared among all the connected users
var portfolioId = "portfolio1";

// portfolio contents; provided by the PORTFOLIO_ADAPTER in COMMAND mode
var schema = ["key", "command", "qty"];

// stock quote details; provided by the QUOTE_ADAPTER in MERGE mode
var underSchema = ["stock_name", "last_price", "time"];

// cell highlighting time (milliseconds)
var hotTime = 500;

// fade effect (can be activated with trailing "fade=ON" in URL
var doFade = (location.search.indexOf("fade=ON") > -1);
var fadeTime = 300;

// create a MultiDynaMetapushTable with the specified schema and underschema
var table = new MultiDynaMetapushTable([portfolioId], schema, "COMMAND", underSchema);

table.setDataAdapter("PORTFOLIO_ADAPTER"); // first-level Data Adapter
table.setUnderDataAdapter("QUOTE_ADAPTER"); // second-level Data Adapter
table.setSnapshotRequired(true);
table.setPushedHtmlEnabled(false);

// add a field with countervalue calculated on the client side
table.onItemUpdate = function (itemPos, updateInfo, itemName) {
  var qty;
  var price;
  var calc = false;
  if (updateInfo.isValueChanged("qty")) {
    qty = updateInfo.getNewValue("qty");
    calc = true;
  } else {
    qty = updateInfo.getOldValue("qty");
  }

  if (updateInfo.isValueChanged("last_price")) {
    price = updateInfo.getNewValue("last_price");
    calc = true;
  } else {
    price = updateInfo.getOldValue("last_price");
  }

  if (price == null || qty == null) {
    calc = false;
  }

  if (calc) {
    // the countervalue field ("c_value") is calculated and added
    // to the message as an extra field
    updateInfo.addField("c_value", qty * price, true);
  }
};

// define visual effects and formatting
table.onChangingValues = function (domNode, visualUpdateInfo) {
  if (visualUpdateInfo != null) {
    
    // visual effects on updates
    visualUpdateInfo.setHotTime(hotTime);
    if (doFade) {
      visualUpdateInfo.setHotToColdTime(fadeTime);
    }

    visualUpdateInfo.setRowStyle("lshot", "lscold");
    visualUpdateInfo.setStyle("qty", "lshotq", "lscoldq");
    visualUpdateInfo.setStyle("stock_name", "lshotl", "lscoldl");
    visualUpdateInfo.setRowAttribute("#ffff66", "#ddffaa", "backgroundColor");

    // format timestamp
    var time = visualUpdateInfo.getFormattedValue("time");
    if (time != null) {
      time = formatTime(time);
      visualUpdateInfo.setFormattedValue("time", time);
    }

    // format prices
    formatNumber("last_price", visualUpdateInfo);
    formatNumber("c_value", visualUpdateInfo);
  }
};

// bind the table to the corresponding HTML template
pushPage.addTable(table, "portfolio");


//////////////// Table Sort Management

var initialSort = "stock_name";
var direction = false; // true = decreasing; false = increasing; null = no sort

function changeSort(sortOn) {
  var sortedBy = table.getMetapushSortFieldName();
  if (sortOn == sortedBy) {
    if (direction == false) {
      direction = true;
      document.getElementById("img_" + sortOn).src = "images/down.gif";
    } else if (direction == true) {
      direction = null;
      document.getElementById("img_" + sortOn).src = "images/spacer.gif";
      document.getElementById("col_" + sortOn).className = "tableTitle";
    } else {
      direction = false;
      document.getElementById("img_" + sortOn).src = "images/up.gif";
    }
  } else {
    direction = false;
    if (sortedBy != null) {
      document.getElementById("img_" + sortedBy).src = "images/spacer.gif";
      document.getElementById("col_" + sortedBy).className = "tableTitle";
    }
    document.getElementById("img_" + sortOn).src = "images/up.gif";
    document.getElementById("col_" + sortOn).className = "tableTitleSorted";
  }

  if (direction == null) {
    table.setMetapushSort(null);
    return;
  } else {
    if (sortOn == "qty" || sortOn == "last_price" || sortOn == "c_value") {
      table.setMetapushSort(sortOn, direction, true, false);
    } else {
      table.setMetapushSort(sortOn, direction);
    }
  }
}

// let's define the initial sorting column
changeSort(initialSort);


//////////////// Formatting Functions

// convert time format from [0-24] to [0-12] (without AM/PM)
function formatTime(val) {
  var a = new Number(val.substring(0,val.indexOf(":")));
  if (a > 12) {
    a -= 12;
  }
  var b = val.substring(val.indexOf(":"),val.length);
  return a + b;
}

// format a decimal number to a fixed number of decimals
function formatDecimal(value, decimals, keepZero) {
  if (isNaN(value)) {
  	// this server-side demo Data Adapter uses "," as a decimal separator
    value = convertCommaToDot(value);
  }
  var mul = new String("1");
  var zero = new String("0");
  for (var i = decimals; i > 0; i--) {
    mul += zero;
  }
  value = Math.round(value * mul);
  value = value / mul;
  var strVal = new String(value);
  if (!keepZero) {
    return strVal;
  }

  var nowDecimals = 0;
  var dot = strVal.indexOf(".");
  if (dot == -1) {
    strVal += ".";
  } else {
    nowDecimals = strVal.length - dot - 1;
  }
  for (var i = nowDecimals; i < decimals; i++) {
    strVal = strVal + zero;
  }

  return strVal;
}

// replace "," with "."
function convertCommaToDot(value) {
  var strValue = new String(value);
  if (strValue.indexOf(",") > -1 ) {
    var strValue=strValue.replace(",",".");
  }
  return new Number(strValue);
}

// helper function for onChangingValues event handlers
function formatNumber(field, itemUpdate, perc, decimals) {
  var newValue = itemUpdate.getFormattedValue(field);
  if (newValue == null) {
    return;
  }

  if (!decimals) {
    decimals = 2;
  }

  var formattedVal = formatDecimal(newValue, decimals, true);

  if (perc) {
    if (formattedVal > 0) {
      formattedVal = "+" + formattedVal;
    }
    formattedVal += "%";
  }
  itemUpdate.setFormattedValue(field,formattedVal);
}
