// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

(function() {
var dumpToTextButton = $('dump-to-text');
var dataDump = $('data-dump');
dumpToTextButton.addEventListener('click', function(event) {
  // TODO(akalin): Add info like Chrome version, OS, date dumped, etc.

  var data = '';
  data += '======\n';
  data += 'Status\n';
  data += '======\n';
  data += JSON.stringify(chrome.sync.aboutInfo, null, 2);
  data += '\n';
  data += '\n';

  data += '=============\n';
  data += 'Notifications\n';
  data += '=============\n';
  data += JSON.stringify(chrome.sync.notifications, null, 2);
  data += '\n';
  data += '\n';

  data += '===\n';
  data += 'Log\n';
  data += '===\n';
  data += JSON.stringify(chrome.sync.log.entries, null, 2);
  data += '\n';

  dataDump.textContent = data;
});

var allFields = [
  'ID',
  'IS_UNSYNCED',
  'IS_UNAPPLIED_UPDATE',
  'BASE_VERSION',
  'BASE_VERSION_TIME',
  'SERVER_VERSION',
  'SERVER_VERSION_TIME',
  'PARENT_ID',
  'SERVER_PARENT_ID',
  'IS_DEL',
  'SERVER_IS_DEL',
  'serverModelType',
  'SERVER_SPECIFICS',
  'SPECIFICS',
];

function versionToDateString(version) {
  // TODO(mmontgomery): ugly? Hacky? Is there a better way?
  var epochLength = Date.now().toString().length;
  var epochTime = parseInt(version.slice(0, epochLength));
  var date = new Date(epochTime);
  return date.toString();
}

/**
 * @param {!Object} node A JavaScript represenation of a sync entity.
 * @return {string} A string representation of the sync entity.
 */
function serializeNode(node) {
  return allFields.map(function(field) {
    var fieldVal;
    if (field == 'SERVER_VERSION_TIME') {
      var version = node['SERVER_VERSION'];
      fieldVal = versionToDateString(version);
    } if (field == 'BASE_VERSION_TIME') {
      var version = node['BASE_VERSION'];
      fieldVal = versionToDateString(version);
    } else if ((field == 'SERVER_SPECIFICS' || field == 'SPECIFICS') &&
            (!$('include-specifics').checked)) {
      fieldVal = 'REDACTED';
    } else if ((field == 'SERVER_SPECIFICS' || field == 'SPECIFICS') &&
            $('include-specifics').checked) {
      fieldVal = JSON.stringify(node[field]);
    } else {
      fieldVal = node[field];
    }
    return fieldVal;
  });
}

/**
 * @param {string} type The name of a sync model type.
 * @return {boolean} True if the type's checkbox is selected.
 */
function isSelectedDatatype(type) {
  var typeCheckbox = $(type);
  // Some types, such as 'Top level folder', appear in the list of nodes
  // but not in the list of selectable items.
  if (typeCheckbox == null) {
    return false;
  }
  return typeCheckbox.checked;
}

function makeBlobUrl(data) {
  var textBlob = new Blob([data], {type: 'octet/stream'});
  var blobUrl = window.URL.createObjectURL(textBlob);
  return blobUrl;
}

function makeDownloadName() {
  // Format is sync-data-dump-$epoch-$year-$month-$day-$OS.csv.
  var now = new Date();
  var friendlyDate = [now.getFullYear(),
                      now.getMonth() + 1,
                      now.getDate()].join('-');
  var name = ['sync-data-dump',
              friendlyDate,
              Date.now(),
              navigator.platform].join('-');
  return [name, 'csv'].join('.');
}

function makeDateUserAgentHeader() {
  var now = new Date();
  var userAgent = window.navigator.userAgent;
  var dateUaHeader = [now.toISOString(), userAgent].join(',');
  return dateUaHeader;
}

/**
 * Builds a summary of current state and exports it as a downloaded file.
 *
 * @param {!Array.<{type: string, nodes: !Array<!Object>}>} nodesMap
 *     Summary of local state by model type.
 */
function triggerDataDownload(nodesMap) {
  // Prepend a header with ISO date and useragent.
  var output = [makeDateUserAgentHeader()];
  output.push('=====');

  var aboutInfo = JSON.stringify(chrome.sync.aboutInfo, null, 2);
  output.push(aboutInfo);

  // Filter out non-selected types.
  var selectedTypesNodes = nodesMap.filter(function(x) {
    return isSelectedDatatype(x.type);
  });

  // Serialize the remaining nodes and add them to the output.
  selectedTypesNodes.forEach(function(typeNodes) {
    output.push('=====');
    output.push(typeNodes.nodes.map(serializeNode).join('\n'));
  });

  output = output.join('\n');

  var anchor = $('dump-to-file-anchor');
  anchor.href = makeBlobUrl(output);
  anchor.download = makeDownloadName();
  anchor.click();
}

function createTypesCheckboxes(types) {
  var containerElt = $('node-type-checkboxes');

  types.map(function(type) {
    var div = document.createElement('div');

    var checkbox = document.createElement('input');
    checkbox.id = type;
    checkbox.type = 'checkbox';
    checkbox.checked = 'yes';
    div.appendChild(checkbox);

    var label = document.createElement('label');
    // Assigning to label.for doesn't work.
    label.setAttribute('for', type);
    label.innerText = type;
    div.appendChild(label);

    containerElt.appendChild(div);
  });
}

function onReceivedListOfTypes(e) {
  var types = e.details.types;
  types.sort();
  createTypesCheckboxes(types);
  chrome.sync.events.removeEventListener(
      'onReceivedListOfTypes',
      onReceivedListOfTypes);
}

document.addEventListener('DOMContentLoaded', function() {
  chrome.sync.events.addEventListener(
      'onReceivedListOfTypes',
      onReceivedListOfTypes);
  chrome.sync.requestListOfTypes();
});

var dumpToFileLink = $('dump-to-file');
dumpToFileLink.addEventListener('click', function(event) {
  chrome.sync.getAllNodes(triggerDataDownload);
});
})();
