/*
 *
 * http://mathworld.wolfram.com/SierpinskiCurve.html
 * http://spanky.fractint.org/pub/fractals/lsystems/fractint.l
 *
 *
 */

// http://arxiv.org/abs/0806.4787
// http://mathworld.wolfram.com/SierpinskiCurve.html

var g_param_sets = [
  { depth: 2, width: 30, type: "sierpinski1", start_x: 15, start_y: 0, start_direction: 0, moduloX: 0, moduloY: 0 }
  ,{ depth: 2, width: 30, type: "sierpinski2", start_x: 15, start_y: 0, start_direction: 0, moduloX: 4, moduloY: 0 }
  ,{ depth: 2, width: 30, type: "sierpinski3", start_x: 15, start_y: 0, start_direction: 0, moduloX: 4, moduloY: 0 }
  ,{ depth: 5, width: 30, type: "hilbert", start_x: 0, start_y: 0, start_direction: 0, moduloX: 0, moduloY: 0 }
  ,{ depth: 2, width: 30, type: "peano1", start_x: 15, start_y: 15, start_direction: 0, modulo: 0}
  ,{ depth: 1, width: 30, type: "koch5", start_x: 0, start_y: 12, start_direction: 0, modulo: 0}
  ,{ depth: 2, width: 30, type: "quadkoch", start_x: 15, start_y: 15, start_direction: 0, moduloX: 1, moduloY: 1}
  ,{ depth: 3, width: 30, type: "fass1", start_x: 0, start_y: 30, start_direction: 0, moduloX: 0, moduloY: 0}
  ,{ depth: 3, width: 30, type: "fass2", start_x: 0, start_y: 30, start_direction: 0, moduloX: 0, moduloY: 0}
//  ,{ depth: 3, width: 30, type: "moore", start_x: 0, start_y: 15, start_direction: 0, modulo: 2 }
];

//var g_param_index = getUrlParam("type") || 0;
var g_param_index = 0;
//alert(g_param_index)
var g_params = g_param_sets[g_param_index];

var g_brightness = .9;
var g_weekendColour = new Colour(.78,.78,1.0);
var g_nextYearColour = new Colour(.97,.97,.97);
var g_bigYearColour = g_weekendColour;


var g_weekDays = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];
var g_monthNames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];

var g_group;
var g_months = [31,28,31,30,31,30,31,31,30,31,30,31];
var g_pathData =[];
var g_count=0;
var g_day=0, g_month=0, g_year=2009, g_day_of_week=2;


//===================================================================================
// L-System
var g_systems =
  {"hilbert":
   {
     rules: {"L":"+RF-LFL-FR+", "R":"-LF+RFR+FL-"},
     axiom: "L",
     closed: false
   },
   "moore":
   {
     rules: {"L":"-RF+LFL+FR-","R":"+LF-RFR-FL+"},
     axiom: "LFL+F+LFL",
     closed: false
   },
   "sierpinski1":
   {
     rules: {"A":"A+A-B+A", "B":"B+A-B+A"},
     axiom: "A+A+A+A",
     closed: true,
     terminals: {"A":"F+FF-FF", "B":"+F-FFF-FF"}
   },
   "sierpinski2":
   {
     rules: {"A":"A+A-B+A", "B":"B+A-B+A"},
     axiom: "A+A+A+A",
     closed: true,
     terminals: {"A":"F+FF-FF", "B":"F+F-F-F+F-F"}
   },
   "sierpinski3":
   {
     rules: {"A":"A+A-B+A", "B":"B+A-B+A"},
     axiom: "A+A+A+A",
     closed: true,
     terminals: {"A":"F+F-F+F-F", "B":"F+F-F-F+F-F"}
   },
   "peano1":
   {
     rules: {"F":"F-F+F+F+F-F-F-F+F"},
     axiom: "F-F-F-F",
     closed: false
   },
   "koch5":
   {
     rules: {"F":"F+F-F-FFF+F+F-F"},
     axiom: "F+F+F+F",
     closed: false
   },
   "quadkoch":
   {
     rules: {"F":"F+FF-FF-F-F+F+FF-F-F+F+FF+FF-F"},
     axiom: "F-F-F-F-",
     closed: false
   },
   "fass1":
   {
     rules: {"L":"LF+RFR+FL-F-LFLFL-FRFR+","R":"-LFLF+RFRFR+F+RF-LFL-FR"},
     axiom: "-L",
     closed: false
   },
   "fass2":
   {
     rules: {"L":"LFLF+RFR+FLFL-FRF-LFL-FR+F+RF-LFL-FRFRFR+","R":"-LFLFLF+RFR+FL-F-LF+RFR+FLF+RFRF-LFL-FRFR"},
     axiom: "-L",
     closed: false
   }
  };

//===================================================================================

function rewrite(s,system)
{
  var s2=[];
  var matching_rule;
  for (var i=0;i<s.length;i++)
  {
    matching_rule=system.rules[s[i]];
    s2.push(matching_rule ? matching_rule : s[i]);
  }
  return s2.join('');
}

//===================================================================================

function run(system,iterations)
{
  var s=system.axiom;
  for (var i=0;i<iterations;i++)
  {
    s=rewrite(s,system);
  }
  s=s.replace(/[LR]/g,"");

  for (var terminal in system.terminals)
  {
    s=s.replace(new RegExp(terminal,"g"),system.terminals[terminal]);
  }
  return s;
}

//==================================================================================

function draw()
{
  g_group = document.getElementById('calendar');
  var s=run(g_systems[g_params.type],g_params.depth);
  var dayColour;
  var x=g_params.start_x, y=g_params.start_y, direction=g_params.start_direction;

  g_group.setAttribute("font-size",g_params.width/5);
  document.getElementById('year').firstChild.data=g_year;
  document.getElementById('year').setAttribute("fill",g_bigYearColour);
  document.getElementById('url').setAttribute("fill",g_bigYearColour);

  if (!g_systems[g_params.type].closed)
  {
    dayColour = (g_day_of_week==5||g_day_of_week==6)?g_weekendColour:{red:.82*g_brightness,green:.82*g_brightness,blue:.82*g_brightness};
    makeMyDay(0,g_params.start_x,g_params.start_y);
    g_day=1; g_day_of_week++;
  }

  for (var i=0; i<s.length; i++)
  {
    switch(s[i])
    {
      case "+": direction = (direction+270) % 360; break;
      case "-": direction = (direction+90) % 360; break;
      case "F":
        switch (direction)
        {
          case   0: makeMyDay(++x,y); if (x==8||x==13||x==17||x==23) makeMyDay(++x,y); break;
          case  90: makeMyDay(x,--y); break;
          case 180: makeMyDay(--x,y); if (x==8||x==13||x==17||x==23) makeMyDay(--x,y); break;
          case 270: makeMyDay(x,++y); break;
        }
      break;
    }
  }
  var path=document.getElementById('polyline');
  path.setAttribute("d",g_pathData.join(' '));
  path.setAttribute("stroke-width",g_params.width-2);
}


var g_firstDay=1;
function makeMyDay(x,y) {
  var dayColour,letter;

  var moveOrLine;
  if (g_firstDay==1) { g_firstDay=0; letter="M"; } else { letter="L"; }
  g_pathData.push(letter + x*g_params.width+' '+y*g_params.width);

  g_count++; g_day++; g_day_of_week++;
  if (g_day_of_week==7) g_day_of_week=0;
  if (g_day > g_months[g_month]) {
    if (++g_month > 11) {
      g_months[1] = (++g_year % 4 == 0) ? 28 : 29;
      g_month=0;
    }
    g_day=1;
  }

  if (g_year > 2009)
  {
    dayColour=g_nextYearColour;
  }
  else
  if (g_day_of_week==5 || g_day_of_week==6)
  {
    dayColour=g_weekendColour;
  }
  else
  {
    switch(g_month%4)
    {
    case 0: dayColour= new Colour(.82, .82, .82); break;
    case 2: dayColour= new Colour(.86, .86, .86); break;
    case 3: dayColour= new Colour(.90, .90, .90); break;
    case 1: dayColour= new Colour(.94, .94, .94); break;
    }
  }
  drawCell(x*g_params.width,
           y*g_params.width,
           dayColour,
           g_weekDays[g_day_of_week],
           g_day,
           g_month);
}

function drawCell(x,y,colour,weekday,day,month)
{
  var rect=document.createElementNS("http://www.w3.org/2000/svg","rect");
  var w=g_params.width;
  rect.setAttribute("x",x-w/2-.2);
  rect.setAttribute("y",y-w/2-.2);
  rect.setAttribute("width",w-.4);
  rect.setAttribute("height",w-.4);
  rect.setAttribute("stroke","none");
  rect.setAttribute("fill",colour);
  g_group.appendChild(rect);

  var text=document.createElementNS("http://www.w3.org/2000/svg","text");
  text.setAttribute("x",x);
  text.setAttribute("y",y+w/2.3);
  text.setAttribute("style","fill:white; text-anchor: middle; dominant-baseline: mathematical");

  var textEl1=document.createElementNS("http://www.w3.org/2000/svg","tspan");
  textEl1.setAttribute("style","font-size:"+g_params.width/8.0);
  textEl1.appendChild(document.createTextNode(weekday+" "));
  text.appendChild(textEl1);

  var textEl2=document.createElementNS("http://www.w3.org/2000/svg","tspan");
  textEl2.setAttribute("style","font-size:"+g_params.width/4.0);
  textEl2.appendChild(document.createTextNode(day));
  text.appendChild(textEl2);

  var textEl3=document.createElementNS("http://www.w3.org/2000/svg","tspan");
  textEl3.setAttribute("style","font-size:"+g_params.width/8.0);
  textEl3.appendChild(document.createTextNode(" "+g_monthNames[month]));
  text.appendChild(textEl3);

  g_group.appendChild(text);
}

//======================================================================
function getUrlParam(name)
{
  var matches=/type=([0-9]+)/.exec(window.location);
  return matches && matches.length == 2 ? matches[1] : null;
}

function Colour(red,green,blue)
{
  this.r=red;  /* 0.0 to 1.0 */
  this.g=green;
  this.b=blue;
  this.toString = function()
  {
    return "rgb("+this.r*100*g_brightness+"%,"+
                  this.g*100*g_brightness+"%,"+
                  this.b*100*g_brightness+"%)";
  };
}

//======================================================================
draw();

