/* Global variables */
var toggles = new Array([1],[2]);
var cosets = new Array([1],[2]);
var perm = new Array([1],[2]);
var selectorline = new Array([1]);
var GType = '';
var FONTSZ = 1;

var unselcol = 'lightgrey';
var selcol = '#ffff00';

var cosetcols = new Array(['#ffff00'],['blue','white'],
                      ['red','white'],
                      ['#ff00ff'],['lime'], ['navy','white'],
                      ['silver'],['teal'],['olive'],['purple','white'],
                      ['aqua'], ['coral'],['orange'],['brown','white'],
                      ['white', 'black'], ['black', 'white'],['green']);

var curg = 0;
var oldgroup;

function getformvalue(fname) {
  var xx = document.forms[0].elements[''+fname];
  if(typeof(xx) == "undefined") return('undefined');
  return(xx.value);
}


function groupmenu() {
  var lst = new Array(1);
  lst[0] = 'Trivial';
  lst.push('V_4');
  lst.push('S_3');
  lst.push('Q_8');
  lst.push('GL_2(Z_2)');
  /*  lst.push('A_4'); */
  /*  lst.push('G_12'); */
  lst.push('S_4');
  var txt = '<select size="1" name="groupname">';
  for(var j=0; j<lst.length; j++) {
    txt += '<option value="'+lst[j]+'">'+lst[j]+'</option>';
  }
  txt += '</select>';
  return(txt);
}

function assoc(a, li) {
  var nn=li.length;
  for(var j=0; j<nn; j++) {
    if(li[j] == a) {
      return(j);
    }
  }
  return(-1);
}


function getn(aninput) {
  if(typeof(aninput) != "undefined") return(aninput);
  var nn = getformvalue('n');
  nn = parseInt(nn);
  if(isNaN(nn)) { return(0);}
//  if(nn<0) { return(0);}
  return(nn);
}

function getnlist(aninput) {
  var nn = getformvalue('listn');
  if(typeof(aninput) != "undefined") nn = aninput;
  if(nn == 'undefined') {return(0);}
  var nlist = nn.split(',');
  var st='';
  
  for(var j=0; j<nlist.length; j++) {
    nlist[j] = parseInt(nlist[j]);
    if(isNaN(nlist[j])) { nlist[j]=0;}
    if(nlist[j]<0) { nlist[j]=0;}
  }
  
  return(nlist);
}
  
function showatable(myinp) {
  /* Set global variables */
  oldgroup = curg;
  curg = getagroup(myinp);
  var n = curg.n;
  for(var j=0; j<n; j++) { toggles[j]=0; }
  resetCosets(n);

  var fsz = curg.fontsize;
  if(typeof(fsz) == "undefined") {
    FONTSZ = 1;
    if(n>10)
      FONTSZ *= Math.pow(10./(n), 0.99);
    if(n<5)
      FONTSZ *= 4./(n);
  } else {
    FONTSZ =fsz;
  }
  resizetable(1);
  
  showtable(curg);
  resetDiagram();
  msg('Selected group '+curg.name);
}

function resetDiagram() {
  if(typeof(oldgroup) != "undefined" && oldgroup) {
    oldgroup.destroy();
  }
  subinfo('Click below to show the subgroup diagram.');
  $('showdiabutton').disabled = false; 
  $('senddiasubbutton').disabled = true;
  writel(curg.name, 'diagroupname');
}

rnd.seed = 1234;
function setseed(sed) {
  rnd.seed = sed;
}

// Modification of:
// The Central Randomizer 1.3 (C) 1997 by Paul Houle (paul@honeylocust.com)
// See:  http://www.honeylocust.com/javascript/randomizer.html
function rnd() {
        rnd.seed = (rnd.seed*9301+49297) % 233280;
        return rnd.seed/(233280.0);
}

function selectorLine(type) {
  var txt = '';
  
  var typeinput=''; // Type of group showing
  typeinput = getformvalue('grouptype');
  if(typeinput == "undefined" || typeinput == '?') typeinput = '';
  if(type == 'new') typeinput = '';
  if(typeinput == '') typeinput = 'zn';
  
  var gtypepart = 'Group Type: ';
  gtypepart += '<select size="1" name="grouptype" onChange="selectorLine(\'type\')">';

  var TYPES = new Array(['zn', 'Z_n ...'],
                        ['dn', 'D_n ...'],
                        ['znstar', 'Z_n^* ...'],
                        ['znprod', 'Z_n1 x Z_n2 x ...'],
                        ['holn', 'Aff(Z_n) ...'],
                        ['order', 'By order ...'],
                        ['mystery', 'Mystery ...']);
/*
  TYPES.push(['Trivial', 'Trival']);
  TYPES.push(['V_4', 'V_4']);
  TYPES.push(['S_3','S_3']);
  TYPES.push(['Q_8','Q_8']);
  TYPES.push(['S_4','S_4']); */
  TYPES.push(['GL_2(Z_2)','GL_2(Z_2)']);

  for(var j=0; j<TYPES.length; j++) {
    gtypepart += '<option value="'+TYPES[j][0]+'"';
    if(TYPES[j][0] == typeinput) { gtypepart += ' selected ';}
    gtypepart += '>'+TYPES[j][1]+'</option>';
  }
  gtypepart += '</select>';

  var nline = ' <i>n</i> = <input name = "n" type="text" size="3"> ';
  /*  var kline = ' <i>k</i> = <input name = "k" type="text" size="3"> '; */
  var niline = ' List n_1,n_2, ...: <input name = "listn" type="text" size="12"> ';
  var showme = '<input type=button value="Show Group" onClick="showatable()">';

  txt = gtypepart;
  switch (typeinput) {
  case 'zn': 
  case 'dn': 
  case 'znstar': 
  case 'holn': txt += nline+showme; GType = typeinput; break;
  case 'misc': txt += groupmenu() +showme; GType = typeinput; break;
  case 'znprod': txt += niline+showme; GType = typeinput; break;
  case 'mystery': 
    var curmaxord = getformvalue('n');
    var curseed = getformvalue('num');
    txt += ' Max. order = <input name = "n" type="text" size="3"';
    if(curmaxord != 'undefined') txt += 'value="'+ curmaxord+'"';
    txt += '> ';
    txt += ' Number (between 1 and 99999): ';
    txt += ' <input name = "num" type="text" size="6"';
    if(curseed != 'undefined') txt += 'value="'+ curseed+'"';
    txt += '>';
    txt += showme; GType = typeinput;
    break;
  case 'order':
    var curorder = getformvalue('groupord');
    if(curorder == 'undefined') curorder = 1;
    var gorderline = ' Order: <select size="1" name="groupord" ';
    gorderline += 'onChange="selectorLine(\'order\')">';
    
    for(var j = 0; j< gorder.length; j++) {
      gorderline += '<option value="'+(j+1)+'"';
      if((j+1) == curorder) gorderline += ' selected ';
      gorderline += '>'+(j+1)+'</option>';
    }
    gorderline += '</select>';
    
    var gordlist = ' <select size="1" name="gentry"> ';
    var gordlistpick = getformvalue('gentry');
    for(var j = 0; j< gorder[curorder-1].length; j++) {
      gordlist += '<option value="'+j+'"';
      if(j == gordlistpick) gordlist += ' selected ';
      gordlist += '>'+gorder[curorder-1][j][2]+'</option>';
    }
    gordlist += '</select>';
    
    txt += gorderline+gordlist+showme;

    GType = typeinput; break;
    break;
  default: 
    txt += showme; GType = typeinput; break;
    break;    
  }

  writel(txt, 'selectors');
}

function msg(mess) {
  writel(mess, 'message');
}

function subinfo(mess) {
  writel(mess, 'subinfo');
}

function myGetById(id) {
  var x;

  if (document.getElementById) {
    x = document.getElementById(id);
  } else if (document.all) {
    x = document.all[id];
  }
  return(x);
}
  

function togglej(j) {
  var x = myGetById('elem'+j);
  if(toggles[j]>0) {
    x.bgColor= unselcol;
    toggles[j]=0;
  } else {
    toggles[j]=1;
    x.bgColor= selcol;
  }
}

function writel(text,id, jsmathflag) {
  var x = myGetById(id);
  x.innerHTML = '';
  x.innerHTML = text;
  /* if(typeof(jsmathflag)!= "undefined" && jsmathflag) 
    jsMath.ProcessBeforeShowing(x); */
}

function smaller () {
  resizetable(0.8);
}

function bigger () {
  resizetable(1.2);
}

function resizetable(factor) {
  var x = myGetById('sizeme');
  var y;
  if (x.currentStyle)
    y = x.currentStyle['font-size'];
  else if (window.getComputedStyle)
    y = document.defaultView.getComputedStyle(x,null).getPropertyValue('font-size');
  if(typeof(y)== "undefined") y= 18;
  
  y = parseFloat(y);
  FONTSZ *= factor;
  var xx = $('output');
  xx.style.fontSize = (y*FONTSZ)+"px";
}


function showtable(g) {
  var txt='';
  var names = g.names;
  var table = g.mul;
  var n = g.n, j, k;
  var oper = g.oper;
  var style = '';

  if(typeof(oper) == "undefined") { oper= '*';}

  txt = '<table class="grouptable" id="thetable"><tr><td class="edgetop">';
  /* Name of group */
  txt += g.name+'<td class="spc">&nbsp;';
  /* Operation */
  txt +=  '<td class="edgetopleft">'+ oper;
  /* Top row */
  for(k=0; k< n; k++) {
    style = cosetColor(cosets[perm[k]]);
    txt += '<td class="edgetop" '+style+'>'+names[perm[k]];
  }
  for(j=0;j< n; j++) {
    /* left column element - set toggle on that element */
    txt += '<tr><td class="elemcol" id="elem'+ j+
      '" onClick="togglej('+j+');return(false)">';
    txt += names[j]+'<td class="spc">';
    
    /* left edge element */
    style = cosetColor(cosets[perm[j]]);
    txt += '<td class="edgeleft" '+style+'>'+ names[perm[j]];
    for(k=0; k< table.length; k++) {
      /* Main body element */
      var prodelem=table[perm[j]][perm[k]];
      style = cosetColor(cosets[prodelem]);
      txt += '<td class="elem" '+style+'>'+names[prodelem];
    }
  }
  txt += '</table>';

  writel(txt, 'output'); /* , g.options.jsMath); */

  setToggles(curg.n);
  selectorLine();
}

function setToggles(n) {
  for(var j=0; j<n; j++) { 
    var x = myGetById('elem'+j);
    if(toggles[j]>0) {      
      x.bgColor= selcol;
    } else {
      x.bgColor= unselcol;
    }
  }
}

function resetCosets(n, noperm) {
  cosets = new Array(n);
  var noperm1 = noperm || false;
  if(! noperm1) perm = new Array(n);
  for(var j=0; j<n; j++) { 
    cosets[j]= -1; 
    if(! noperm1) perm[j]= j;
  }
}

function clearsel() {
  if(curg != 0) {
    var n = curg.n;
    for(var j=0; j<n; j++) { toggles[j]=0; }
    setToggles(n);
    resetCosets(n);
    showtable(curg);
    msg('Cleared element selections');
  } else {
    msg('Nothing to do');
  }
}

function test () {
  var g1 = cyclic(5);
  var g2 = cyclic(4);
  
  g2.genconnecthom(g1, [[1,[[1,2]]]]);
}

/*   Group operartions */

function cc () {
  var n = curg.n;
  var mul = curg.mul;
  var changed=0;
  var nw, j, k;
  for(j=0; j<n; j++) {
    if(toggles[j]>0) {
      for(k=0; k<n; k++) {
        nw = curg.conj(j,k);
        if(toggles[nw]==0) {
          togglej(nw);
          changed=1;
        }
      }
    }
  }
  resetCosets(curg.n, true);
  showtable(curg);
  msg('&nbsp;');
  if(changed == 0) msg('Already closed under conjugation');
}

function gensub () {
  var mysub = new Subgroup(curg,toggles, 'toggles');
  mysub.gensub();
  toggles = mysub.toggles;
  setToggles(curg.n);
  doCosets();
  showtable(curg);
  msg('Generated subgroup');
  if(mysub.changed == 0) msg('Already a subgroup');
}

function centralizer () {
  toggles = curg.centralizer(toggles);
  doCosets();
  showtable(curg);
  msg('Computed centralizer');
}

function seegens () {
  msg(curg.gens2perms());
}

function diagram () {
  curg.drawsubs();
  subinfo('Click on a subgroup to see information about it.');
  msg('Displayed diagram');
}

function subtotable() {
  var mysub = curg.subdiagram.selectedSub();
  toggles = mysub.toggles;
  setToggles(curg.n);
  doCosets();
  showtable(curg);
  $('maintabbergroup').tabber.tabShow(0);
  /* document.getElementById('maintabbergroup').tabber.tabShow(0); */
  msg('Showing subgroup from subgroup diagram.');
}

function subtodiagram() {
  $('maintabbergroup').tabber.tabShow(1);
  curg.drawsubs();
  var diagram = curg.subdiagram;
  var mysub = new Subgroup(curg,toggles, 'toggles');
  var mysub2 = new Subgroup(curg,toggles, 'toggles');
  mysub.gensub();
  if(mysub.isSame(mysub2)) {
    var mynode = diagram.nodeFromSub(mysub);
    diagram.unselectNodes();
    mynode.select();
    diagram.draw();
    showsubinfo(mynode);
    $('senddiasubbutton').disabled = false;    
  } else {
    msg('You need to have a subgroup selected first to send it to the subgroup diagram.');
    return('');
  }
  
}

function commut () {
  toggles = curg.setcomms(toggles, toggles);
  resetCosets(curg.n, true);
  showtable(curg);
  msg('Computed commutator set');
}

function commutG () {
  var allg = new Array(curg.n);
  for(var j=0; j<curg.n; j++) allg[j]=1;
  toggles = curg.setcomms(allg, toggles);
  resetCosets(curg.n, true);
  showtable(curg);
  msg('Computed commutator set');
}


/* Read a subgroup from toggles and generate the permutation of
   elements and assign coset numbers */
function doCosets () {
  var k=0,j,l;
  var cnum=0;
  var nel =0;
  var n = curg.n;
  resetCosets(n);
  
  /* First pick off the subgroup */
  for(j=0; j<n; j++) {
    if(toggles[j]>0) {
      perm[k] = j;
      k++;
      cosets[j] = cnum;
    }
  }
  for(j=0; j<n; j++) {
    if(cosets[j] <0) { /* This is a new element */

      cnum++;
      for(l=0; l<n; l++) {
        if(toggles[l]>0) {
          nel = curg.mul[j][l];
          perm[k] = nel;
          k++;
          cosets[nel] = cnum;
        }
      } /* End of run through new coset */
    }
  }
  
}

function randcolor() {
  var r,g,b;
  r=Math.floor(Math.random()*256);
  g=Math.floor(Math.random()*256);
  b=Math.floor(Math.random()*256);
  var str = 'style="background-color: rgb('+r+','+g+','+b+')"';
  return(str);
}


/* Take a color index and return a string for its colors */
function cosetColor (k) {
  var txt='';
  var bg = 'white';
  var fg = 'black';
  if(k<0) { return('') }
  if(k>=cosetcols.length) { return(randcolor()); }
  if(typeof(k) == "undefined") {
    return('');
  }
  

  bg = cosetcols[k][0];
  if(typeof(cosetcols[k][1]) != "undefined") {
    fg = cosetcols[k][1];
  }
  return('style="background-color: '+ bg+'; color: '+fg+'"');
}
