// *** data
var stateAlert=false;  // Display alert, also if everything worked fine
var stateDebug=false;  // Display debug alert

var modIdx=0;
var modData=new Array();
var modLen=0;

var orgIdx=0;
var orgLen=orgData.length;

var typeLen=typeData.length;

var displayHeader='<tr><th>Number</th><th>Type</th><th>Description</th><th>Usage</th><th>Actions</th></tr>';

var htmlAmp = /&/g;
var htmlQuote = /"/g;
var htmlLT = /</g;
var htmlGT = />/g;

// *** trim functions
function trimString(str) {
  var strIdx=0;
  var strLen=str.length;

  // Leading spaces
  while ( strIdx<strLen && str.charAt(strIdx)==' ' ) { strIdx++; }
  if ( strIdx>0 ) {
  	str=str.substring(strIdx,strLen);
    strLen=str.length;
  }

  // Trailing spaces
  strIdx=strLen-1;
  while ( strIdx>=0 && str.charAt(strIdx)==' ' ) { strIdx--; }
  strIdx++;
  if ( strIdx<strLen ) { str=str.substr(0,strIdx); }

  return(str);
}

function trimNumber(number) {
  for( var i=(numSize-number.length); i>0; i-- ) { number='0'+number; }

  return(number.toUpperCase());
}

// *** functions to check and change data
function checkHexNumber(number) {
  var digit;
  for (var i=number.length, strIdx=0; i>0; i-- ) {
    digit=number.charAt(strIdx++);
    if ( ( digit!='0' ) && ( digit!='1' )
      && ( digit!='2' ) && ( digit!='3' )
      && ( digit!='4' ) && ( digit!='5' )
      && ( digit!='6' ) && ( digit!='7' )
      && ( digit!='8' ) && ( digit!='9' )
      && ( digit!='A' ) && ( digit!='B' )
      && ( digit!='C' ) && ( digit!='D' )
      && ( digit!='E' ) && ( digit!='F' ) ) { return(false); }
  }
  return(true);
}

function findOrgEntry(number) {
  orgIdx=0;
  var orgNumber;
  for ( var i=orgLen; i>0; i-- ) {
    orgNumber=orgData[orgIdx][idxNum];
    if ( orgNumber==number ) { return(true); }
    else if ( orgNumber>number ) { return(false); }
    orgIdx++;
  };
  return(false);
}

function findModEntry(number) {
  modIdx=0;
  var modNumber;
  for ( var i=modLen; i>0; i-- ) {
    modNumber=modData[modIdx][idxNum];
    if ( modNumber==number ) { return(true); }
    else if ( modNumber>number ) { return(false); }
    modIdx++;
  };
  return(false);
}

function resetEntry(number) {
  number = trimString(number);
  if ( number.length==0 ) {
    alert('Number not entered');
    return(false);
  }
  number = trimNumber(number);
  if ( !checkHexNumber(number) ) {
    alert('Number illegal');
    return(false);
  }

  var orgExists=findOrgEntry(number);
  var modExists=findModEntry(number);
  if ( !modExists ) {
    if ( orgExists ) {
      alert('Sound number ' + number + ' is already in its original state');
    } else {
      alert('Sound number ' + number + ' doesn\'t exist, can\'t reset');
    }
    return(false);  // no change
  }

  if ( !orgExists ) {
    alert('New sound number ' + number + ' can\'t be reset, it\'s new');
    return(false);  // no change
  }

  modData[modIdx][idxNum]='';
  modData.sort();
  modData.shift();
  modLen=modData.length;
  if ( stateAlert ) { alert('Sound number ' + number + ' set back to original definition'); }
  return(true);  // changed
}

function deleteEntry(number) {
  number = trimString(number);
  if ( number.length==0 ) {
    alert('Number not entered');
    return(false);
  }
  number = trimNumber(number);
  if ( !checkHexNumber(number) ) {
    alert('Number illegal');
    return(false);
  }

  var orgExists=findOrgEntry(number);
  var modExists=findModEntry(number);

  if ( !orgExists ) {
    if ( !modExists ) {
      alert('New sound number ' + number + ' doesn\'t exist, can\'t delete');
      return(false);  // no change
    }
    modData[modIdx][idxNum]='';
    modData.sort();
    modData.shift();
    modLen=modData.length;
    if ( stateAlert ) { alert('New sound number ' + number + ' deleted'); }
    return(true);  // changed
  }

  if ( modExists ) {
    if ( modData[modIdx][idxDel] ) {
      alert('Sound number ' + number + ' already deleted');
      return(false);  // no change
    }
    modData[modIdx][idxType]='';
    modData[modIdx][idxDesc]='';
    modData[modIdx][idxUsage]='';
    modData[modIdx][idxDel]=true;
    if ( stateAlert ) { alert('Sound number ' + number + ' deleted'); }
    return(true);  // changed
  }

  modData[modLen]=new Array(number,'','','',true);
  modData.sort();
  modLen=modData.length;
  if ( stateAlert ) { alert('Sound number ' + number + ' deleted'); }
  return(true);  // changed
}

function updateEntry(number, type, desc, usage) {
  number = trimString(number);
  if ( number.length==0 )
  {
    alert('Number not entered');
    return(false);
  }
  number = trimNumber(number);
  if ( !checkHexNumber(number) )
  {
    alert('Number illegal');
    return(false);
  }
  desc = trimString(desc);
  if ( desc.length==0 )
  {
    alert("Description not entered.\nUse the delete button if you want to delete this number.");
    return(false);
  }
  usage = trimString(usage);

  if ( stateDebug )
  {
    alert('Update '+number+':'+type+','+desc+','+usage);
  }

  // Find the corresponding entry in arrays
  var orgExists=findOrgEntry(number);
  var modExists=findModEntry(number);

  // Special case: If changed entry exists in orgData and it has the same definition
  if ( orgExists )  // same key
  {
    if ( ( orgData[orgIdx][idxType]==type )  // same definitions
         && ( orgData[orgIdx][idxDesc]==desc )
         && ( orgData[orgIdx][idxUsage]==usage ) )
    {
      if ( !modExists )
      {
        alert('Sound number ' + number + ' is originally defined this way');
        return(true);  // changed
      }

      modData[modIdx][idxNum]='';
      modData.sort();
      modData.shift();
      modLen=modData.length;
      alert('Sound number ' + number + ' was originally defined this way');
      return(true);  // changed
    }
  }

  // Define some strings for messages
  var soundPrefix='Sound number ';
  if ( !orgExists )
  {
    soundPrefix='New sound number ';
  }
  var soundSuffix=' changed';

  // If changed entry does not exist in modData then append it to the modData array and re-sort
  if ( !modExists )
  {
    modData[modLen]=new Array(number,type,desc,usage,false);
    modData.sort();
    modLen=modData.length;

    if ( !orgExists )
    {
      soundSuffix=' added';
    }
    if ( stateAlert ) { alert(soundPrefix + number + soundSuffix); }
    return(true);  // changed
  }

  if ( ( modData[modIdx][idxType]==type )  // same definitions
       && ( modData[modIdx][idxDesc]==desc )
       && ( modData[modIdx][idxUsage]==usage )
       && ( !modData[modIdx][idxDel] ) )
  {
    alert(soundPrefix + number + ' is already defined this way');
    return(true);  // changed
  }

  modData[modIdx][idxType]=type;
  modData[modIdx][idxDesc]=desc;
  modData[modIdx][idxUsage]=usage;
  modData[modIdx][idxDel]=false;
  if ( stateAlert ) { alert(soundPrefix + number + soundSuffix); }
  return(true);  // changed
}



// *** display functions
function displayOrgData() {
  var orgDataList='OrgData:\n';

  for ( orgIdx=0; orgIdx<orgLen; orgIdx++ ) {
    orgDataList = orgDataList
                  + orgData[orgIdx][idxNum] + ':'
                  + orgData[orgIdx][idxType] + ','
                  + orgData[orgIdx][idxDesc] + ','
                  + orgData[orgIdx][idxUsage] + '\n';
  }
  alert(orgDataList);
}

function displayModData() {
  var modDataList='ModData:\n';

  for ( modIdx=0; modIdx<modLen; modIdx++ ) {
    modDataList = modDataList
                  + modData[modIdx][idxNum] + ':'
                  + modData[modIdx][idxType] + ','
                  + modData[modIdx][idxDesc] + ','
                  + modData[modIdx][idxUsage] + ','
                  + modData[modIdx][idxDel] + '\n';
  }
  alert(modDataList);
}

function htmlizeString(str) {
  return(str.replace(htmlAmp, '&amp;').replace(htmlQuote, '&quot;').replace(htmlLT, '&lt;').replace(htmlGT, '&gt;'));
}

function displayNumber(number) {
  return('<input type="text" name="number' + number + '" size="' + numSize + '" maxlength="' + numSize + '">');
}

function displayType(number, type) {
  var typeOption;
  var htmlEntry = '<select size="1" name="type' + number + '">';
  for ( var i=typeLen, typeIdx=0; i>0; i-- ) {
    typeOption=typeData[typeIdx++];
    htmlEntry = htmlEntry + '<option';
    if ( typeOption==type ) {
      htmlEntry = htmlEntry + ' selected';
    }
    htmlEntry = htmlEntry + '>' + htmlizeString(typeOption) + '</option>';
  }
  return(htmlEntry+'</select>');
}

function displayDesc(number, desc) {
  return('<input type="text" size="40" maxsize="100" name="desc' + number + '" value="' + htmlizeString(desc) + '">');
}

function displayUsage(number, usage) {
  return('<input type="text" size="40" maxsize="100" name="usage' + number + '" value="' + htmlizeString(usage) + '">');
}

function displayUpdateButton(number) {
  return('<input type="button" value="Update" onClick="if ( parent.updateEntry(\'' + number + '\', this.form.type' + number + '.options[this.form.type' + number + '.selectedIndex].text, this.form.desc' + number + '.value, this.form.usage' + number + '.value) ) { document.location.href=document.location.href; }">');
}

function displayDeleteButton(number) {
  return('<input type="button" value="Delete" onClick="if ( parent.deleteEntry(\'' + number + '\') ) { document.location.href=document.location.href; }">');
}

function displayResetButton(number) {
  return('<input type="button" value="Reset" onClick="if ( parent.resetEntry(\'' + number + '\') ) { document.location.href=document.location.href; }">');
}

function displaySingleEntry(singleEntry, number, color) {
  return('<tr bgcolor="'+color+'"><td>'
         + number+'</td><td>'
         + displayType(number, singleEntry[idxType])+'</td><td>'
         + displayDesc(number, singleEntry[idxDesc])+'</td><td>'
         + displayUsage(number, singleEntry[idxUsage])+'</td><td>'
         + displayUpdateButton(number)+' '
         + displayDeleteButton(number)+'</td></tr>');
}

function displayModEntry(orgEntry, modEntry, number) {
  var htmlEntry, org, mod;
  // Number
  if ( modEntry[idxDel] ) { htmlEntry = '<tr bgcolor="red"><td><strike>' + number + '</strike></td><td>'; }
  else { htmlEntry = '<tr bgcolor="silver"><td>' + number + '</td><td>'; }
  // Type
  org=orgEntry[idxType];
  mod=modEntry[idxType];
  if ( org==mod ) { htmlEntry = htmlEntry + displayType(number, org) + '</td><td>'; }
  else { htmlEntry = htmlEntry + displayType(number, mod) + '<br><small>(was: ' + org + ')</small></td><td>'; }
  // Description
  org=orgEntry[idxDesc];
  mod=modEntry[idxDesc];
  if ( org==mod ) { htmlEntry = htmlEntry + displayDesc(number, org) + '</td><td>'; }
  else { htmlEntry = htmlEntry + displayDesc(number, mod) + '<br><small>(was: ' + org + ')</small></td><td>'; }
  // Usage
  org=orgEntry[idxUsage];
  mod=modEntry[idxUsage];
  if ( org==mod ) { htmlEntry = htmlEntry + displayUsage(number, org); }
  else { htmlEntry = htmlEntry + displayUsage(number, mod) + '<br><small>(was: ' + org + ')</small>'; }
  // Actions
  htmlEntry = htmlEntry + '</td><td>' + displayUpdateButton(number) + ' ';
  if ( !modEntry[idxDel] ) { htmlEntry = htmlEntry + displayDeleteButton(number) + ' '; }
  htmlEntry = htmlEntry + displayResetButton(number) + '</td></tr>';

  return(htmlEntry);
}

function createTable(docData) {
  var output='';
  if ( stateDebug ) {
     var t0=new Date().getTime();
     output+='Begin of display at '+t0+'<br>';
  }
  output+='Creation date of &quot;original&quot; data: '+orgCreated+'<br>';
  output+='<table border="1" bgcolor="white"><tr><td><small>Legend:</small></td><td><small>unchanged</small></td><td bgcolor="silver"><small>changed</small></td><td bgcolor="lightgreen"><small>added</small></td><td bgcolor="red"><small>deleted</small></td></tr></table>';
  output+='<form><table border="1" bgcolor="white">';
  output+=displayHeader;
  modIdx=0;
  var modEntry, modNumber;
  if ( modIdx<modLen ) { modEntry=modData[modIdx]; modNumber=modEntry[idxNum]; }
  orgIdx=0;
  var orgEntry, orgNumber;
  for ( var i=orgLen; i>0; i-- ) {
    orgEntry=orgData[orgIdx++]; orgNumber=orgEntry[idxNum];
    while ( modIdx<modLen && modNumber<orgNumber ) {
      output+=displaySingleEntry(modEntry, modNumber, 'lightgreen');
      modEntry=modData[++modIdx]; if ( modIdx<modLen ) { modNumber=modEntry[idxNum]; }
    }
    if ( modIdx<modLen && modNumber==orgNumber ) {
      output+=displayModEntry(orgEntry, modEntry, orgNumber);
      modEntry=modData[++modIdx]; if ( modIdx<modLen ) { modNumber=modEntry[idxNum]; }
    } else {
      output+=displaySingleEntry(orgEntry, orgNumber, 'white');
    }
  }
  while ( modIdx<modLen ) {
    output+=displaySingleEntry(modEntry, modNumber, 'lightgreen');
    modEntry=modData[++modIdx]; if ( modIdx<modLen ) { modNumber=modEntry[idxNum]; }
  }
  output+='</table></form>';
  if ( stateDebug ) {
    var t1=new Date().getTime();
    output+='End of display at '+t1+' ('+(t1-t0)+')<br>';
  }
  docData.writeln(output);
}

function createModDataText(docData) {
  var modEntry, modNumber;
  modIdx=0;
  for ( var i=modLen; i>0; i-- ) {
    modEntry=modData[modIdx++]; modNumber=modEntry[idxNum];
    if ( modEntry[idxDel] ) {
      docData.writeln('DEL: ' + modNumber + ';');
    } else {
      var orgExists=findOrgEntry(modNumber);
      if ( !orgExists ) {
        docData.write('NEW: ');
      } else {
        docData.write('UPD: ');
      }
      docData.writeln(modNumber + ';'
                      + '"' + htmlizeString(modEntry[idxType]) + '";'
                      + '"' + htmlizeString(modEntry[idxDesc]) + '";'
                      + '"' + htmlizeString(modEntry[idxUsage]) + '";');
    }
  }
}

function createSoundsDat(docData) {
  docData.writeln('Copy this into your PinMame sounds.dat file:<br>');
  docData.writeln('<pre>');
  docData.writeln(mapName+'_'+mapVersion+':');
  modIdx=0;
  var orgEntry, orgNumber;
  var modEntry, modNumber;
  if ( modIdx<modLen ) { modEntry=modData[modIdx]; modNumber=modEntry[idxNum]; }
  orgIdx=0;
  var orgEntry, orgNumber;
  for ( var i=orgLen; i>0; i-- ) {
    orgEntry=orgData[orgIdx++]; orgNumber=orgEntry[idxNum];
    while ( modIdx<modLen && modNumber<orgNumber ) {
      if ( !modEntry[idxDel] ) {
        docData.writeln(':'+modNumber+':'+modEntry[idxDesc]);
      }
      modEntry=modData[++modIdx]; if ( modIdx<modLen ) { modNumber=modEntry[idxNum]; }
   }
    if ( modIdx<modLen && modNumber==orgNumber ) {
      if ( !modEntry[idxDel] ) {
        docData.writeln(':'+modNumber+':'+modEntry[idxDesc]);
      }
      modEntry=modData[++modIdx]; if ( modIdx<modLen ) { modNumber=modEntry[idxNum]; }
    } else {
      docData.writeln(':'+orgNumber+':'+orgEntry[idxDesc]);
    }
  }
  while ( modIdx<modLen ) {
    if ( !modData[modIdx][idxDel] ) {
      docData.writeln(':'+modNumber+':'+modEntry[idxDesc]);
    }
    modEntry=modData[++modIdx]; if ( modIdx<modLen ) { modNumber=modEntry[idxNum]; }
  }
  docData.writeln('</pre>');
}

function curAlertStateForButton() {
  if ( stateAlert ) { return('Switch to &quot;Messages only on errors&quot;'); }
  else { return('Switch to &quot;Confirmation also on success&quot;'); }
}

function curDebugStateForButton() {
  if ( stateDebug ) { return('Switch to &quot;Debug off&quot;'); }
  else { return('Switch to &quot;Debug on&quot;'); }
}

function checkUnload() {
  if ( modLen>0 ) { alert('As you left or reload the main sound map page you have lost all changed data.\nI hope you have submitted your changes before.'); }
}
