<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Moonlight Sudoku" 
  author="Miguel de Icaza"
  author_email="miguel@novell.com"
  author_affiliation="Novell, Inc."
  author_location="Some place in La Mancha"
  category="games"
  category2="silverlight"
  screenshot="http://hosting.gmodules.com/ig/gadgets/file/113365436584120763554/Sudoku.png"
  thumbnail="http://hosting.gmodules.com/ig/gadgets/file/113365436584120763554/thumb.png"
  description="Sudoku game, using Silverlight"
  height="200"
  width="200"
  scaling="true"
  />
  <UserPref name="showguides" display_name="Show Guidelines"
            datatype="bool" default_value="true"/>
  <UserPref name="flagerrors" display_name="Flag Errors"
            datatype="bool" default_value="true"/>
<Content type="html"><![CDATA[
<script src="http://hosting.gmodules.com/ig/gadgets/file/113365436584120763554/Silverlight.js" type="text/javascript">
</script>
<script type="text/javascript">
var dingus;

function Sudoku (_control) {
        var misses = 0;
        //
        // Internals
        //
        var prefs = new _IG_Prefs (__MODULE_ID__);
        var pref_showguides = (prefs.getString ('showguides') == '1');
        var pref_flagerrors = (prefs.getString ('flagerrors') == '1');

        var userColor = "#777777";
        var control = _control;
        var content = control.content;
  dingus = content;
        var rootCanvas = content.findName ("sudokuSurface");
        var message = content.findName ("dingus");
        var rowRect = content.findName ("rowRect");
        var colRect = content.findName ("colRect");

        var storyCol = content.findName ("storyCol");
        var splineCol = content.findName ("splineCol");
        var splineRow = content.findName ("splineRow");

        var startx = 0, starty = 0, width = 0, height = 0, cellsize;

        message.Text = ""; //prefs.getString ('showguides');

        solution = [[2, 7, 9, 3, 1, 6, 8, 5, 4],
                    [3, 8, 5, 2, 7, 4, 6, 1, 9],
                    [1, 4, 6, 8, 5, 9, 2, 3, 7],
                    [7, 2, 4, 5, 9, 1, 3, 8, 6],
                    [9, 3, 8, 7, 6, 2, 1, 4, 5],
                    [6, 5, 1, 4, 3, 8, 9, 7, 2],
                    [5, 9, 2, 1, 8, 7, 4, 6, 3],
                    [8, 6, 3, 9, 4, 5, 7, 2, 1],
                    [4, 1, 7, 6, 2, 3, 5, 9, 8]];

        start =    [[0, 7, 0, 0, 0, 0, 8, 0, 0],
                    [0, 0, 0, 2, 0, 4, 0, 0, 0],
                    [0, 0, 6, 0, 0, 0, 0, 3, 0],
                    [0, 0, 0, 5, 0, 0, 0, 0, 6],
                    [9, 0, 8, 0, 0, 2, 0, 4, 0],
                    [0, 5, 0, 0, 3, 0, 9, 0, 0],
                    [0, 0, 2, 0, 8, 0, 0, 6, 0],
                    [0, 6, 0, 9, 0, 0, 7, 0, 1],
                    [4, 0, 0, 0, 0, 3, 0, 0, 0]];

        var current = [];
        var currentText = [];
        var marks = [];
        var Reset = function (){
                misses = 0;

                for (i = 0; i < 9; i++){
                        current [i] = [];
                        currentText [i] = [];
                        marks [i] = [];
                        for (j = 0; j < 9; j++){
                                current [i][j] = start [i][j];
                                currentText [i] = [];
                                marks [i][j] = []; 
                                for (m = 0; m < 9; m++) 
                                        marks [i][j][m] = [];
                        }
                }
        };

        Reset();
        current [0][0] = 2;

        content.OnResize = function () {
        }


        var Rectangle = function (where, x, y, w, h, st, color) {
                return content.createFromXaml (
                        String.concat (
                                "<Rectangle Canvas.Left='", x, "' Canvas.Top='", y, "' Width='", w, "' Height='", h,
                                "' Stroke='", color, "' StrokeThickness='", st, "'/>"));
        }

        var Line = function (where, x1, y1, x2, y2, st, color){
 dingus.createFromXaml ("<Rectangle/>");
                return content.createFromXaml (
                        String.concat (
                                "<Line X1='", x1, "' Y1='", y1, "' X2='", x2, "' Y2='", y2,
                                "' Stroke='", color, "' StrokeThickness='", st, "'/>"));
        }

        var Add = function (child){
                rootCanvas.children.Add (child);
        }

        var Text = function (x, y, val, color, size){
                var s = String.concat ("<TextBlock Text='", val,
                                   "' Canvas.Left='", x,
                                   "' Canvas.Top='", y, "' Foreground='", color,
                                   "' FontSize='", size, "'/>");
                return content.createFromXaml (s);
        }

        var AtCell = function (col, row, val, color){ 
                var t = Text (startx + col*cellsize + cellsize*0.2, starty+row*cellsize, val, color, cellsize * 0.9);
                Add (t);
                return t;
        }

        var AtCellSub = function (col, row, col2, row2, val, color){
                var adjust = cellsize / 3 * 0.1;
                var basex = startx + col*cellsize + 2 * adjust;
                var basey = starty + row*cellsize + adjust;

                var t = Text (basex + (col2 * cellsize / 3), basey + (row2 * cellsize / 3),  val, color, cellsize * 0.25);
                Add (t);
                return t;
        }

        var SetValue = function (col, row, v){
                // clear any markers
                for (m = 0; m < 9; m++){
                        if (marks [row][col][m] != 0)
                                rootCanvas.children.remove (marks [row][col][m]);
                        marks [row][col][m] = 0;
                }

                // update + draw
                current [row][col] = v;
                if (currentText [row][col])
                        rootCanvas.children.Remove (currentText [row][col]);

                var color = userColor;

                if (solution [row][col] != v && pref_flagerrors != 1){
                        misses++;
                        color = "red";
                }

                currentText [row][col] = AtCell (col, row, v, color);
        }

        var DrawSudoku = function (s) {
                var swidth = content.ActualWidth;
                var sheight = content.ActualHeight;

                if (swidth > sheight){
                        width = sheight;
                        height = sheight;
                        startx = (swidth-sheight)/2;
                        starty = 0;
                } else {
                        width = swidth;
                        height = swidth;
                        starty = (height-width)/2;
                        startx = 0;
                }
                cellsize = width / 9;
         
                //rootCanvas.children.Clear ();

                for (i = 0; i < 9; i++){
                        if (i % 3 == 0){
                                color = "#777777";
                                stroke = 2;
                        } else {
                                color = "#aaaaaa";
                                stroke = 1;
                        }
                        Add (Line (rootCanvas,
                                   startx,       starty+(i*cellsize),
                                   startx+width, starty+(i*cellsize), stroke, color));

                        Add (Line (rootCanvas,
                                   startx+(i*cellsize), starty,
                                   startx+(i*cellsize), starty + height, stroke, color));
                }

                Add (Rectangle (rootCanvas, startx, starty, width, height, 2, "black"));

                for (row = 0; row < 9; row++){
                        var color="red";

                        for (col = 0; col < 9; col++){
                                if (current [row][col] == 0)
                                        continue;
                                if (start [row][col] == 0){
                                        color = userColor;
                                } else
                                        color = "black";
                                currentText [row][col] = AtCell (col, row, current [row][col], color);
                        }
                }

                rowRect.setValue ("Canvas.Left", startx);                  
                rowRect.Height = height/9;
                rowRect.Width = width;
                colRect.setValue ("Canvas.Top", starty);
                colRect.Width = width/9;
                colRect.Height = height;

                if (!pref_showguides){
                    colRect.Opacity = 0;
                    rowRect.Opacity = 0;
                }
        }

        var lastX = -1;
        var lastY = -1;
        var lastTime = new Date ().getTime ();

        //
        // Handle click, doubleclick
        //
        rootCanvas.addEventListener ("MouseLeftButtonUp",  function (sender, args){
                var x = args.GetPosition(sender).X - startx;
                var y = args.GetPosition(sender).Y - starty;

                if (x < 0 || y < 0 || x > width || y > height)
                        return;
                        
                var isDouble = false;
                now = new Date ().getTime ();

                if (lastX != -1){
                        isDouble = (Math.abs (x-lastX) < 3) && (Math.abs (y-lastY) < 3) && (now-lastTime  < 400);
                }
                //message.Text = "isDouble: " + isDouble;
                lastX = x;
                lastY = y;
                lastTime = now;

                var cellx = Math.floor (x/cellsize);
                var celly = Math.floor (y/cellsize);

                var subx = Math.floor ((x - cellx * cellsize) / (cellsize / 3));
                var suby = Math.floor ((y - celly * cellsize) / (cellsize / 3));
                var n = suby * 3 + subx;

                if (start [celly][cellx] != 0)
                        return;

                if (marks [celly][cellx][n] != 0){
                        if (isDouble)
                                SetValue (cellx, celly, n+1);
                        else {
                                rootCanvas.children.remove (marks [celly][cellx][n]);
                                marks [celly][cellx][n] = 0;
                        }
                } else {
                        if (currentText [celly][cellx])
                                rootCanvas.children.remove (currentText [celly][cellx]);

                        marks [celly][cellx][n] = AtCellSub (cellx, celly, subx, suby, n+1, "black");
                }
        });

        //
        // Mouse motion
        //
        var targetCol = -1;
        var targetRow = -1;
        var UpdateBars = function (sender, args){
                var x = args.GetPosition(sender).X - startx;
                var y = args.GetPosition(sender).Y - starty;
  
                if (x < 0 || y < 0 || x > width || y > height)
                        return;
                        
                var cellx = Math.floor (x/cellsize);
                var celly = Math.floor (y/cellsize);

                // if ugly, immediate feedback:
                //colRect.setValue ("Canvas.Left", startx + cellx * cellsize);
                //rowRect.setValue ("Canvas.Top", starty + celly * cellsize);

                if (targetCol != cellx || targetRow != celly){
                        splineCol.Value = startx + cellx * cellsize;
                        splineRow.Value = starty + celly * cellsize;

                        storyCol.Begin ();
                        targetCol = cellx;
                        targetRow = celly;
                }
        }

        rootCanvas.addEventListener ("MouseMove", UpdateBars);

        return {
                Reset: Reset,

                Start: function () {
                        DrawSudoku ();
                }
        }
}

function onLoad ()
{
  var control = document.getElementById('silverlight');
  var s = new Sudoku (control);
  s.Start ();
}
</script>
<script type="text/xaml" id='rootxaml'><?xml version="1.0"?>
        <Canvas
           xmlns="http://schemas.microsoft.com/client/2007"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           Width="297" Height="297"
           Background="#ffffff"
           x:Name="sudokuSurface"

         >
        <Canvas.Resources>
          <Storyboard x:Name="storyCol" Duration="0:0:10">
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="colRect"
              Storyboard.TargetProperty="(Canvas.Left)"
              Duration="0:0:0.5">
              <SplineDoubleKeyFrame Value="270" KeySpline="0.0,0.9 1,1" KeyTime="0:0:0.5" x:Name="splineCol"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames
              Storyboard.TargetName="rowRect"
              Storyboard.TargetProperty="(Canvas.Top)"
              Duration="0:0:0.5">
              <SplineDoubleKeyFrame Value="270" KeySpline="0.0,0.9 1,1" KeyTime="0:0:0.5" x:Name="splineRow"/>
            </DoubleAnimationUsingKeyFrames>
          </Storyboard>
        </Canvas.Resources>

        <TextBlock Text="Dingus" x:Name="dingus"/>
        <Rectangle x:Name="rowRect" Canvas.Top="0" Canvas.Left="0" Width="297" Height="33" Fill="#c7d0ff"/>
        <Rectangle x:Name="colRect" Canvas.Top="0" Canvas.Left="0" Width="33"  Height="297" Fill="#c7d0ff"/>
</Canvas>
</script>
<embed type="application/x-silverlight"
  id="silverlight"
  OnLoad="onLoad"
  source="#rootxaml"
  />
<div id="silverlight">
  <script type="text/javascript">
function xaml_error(sender, args)
{
     alert (String.concat ("Error: " + args.ErrorMessage + " at: " + args.LineNumber));
}

    Silverlight.createObjectEx({
        source: "#rootxaml",
        parentElement: document.getElementById("host"),
        id: "silverlight",
        properties: { width:'297', height:'297', version: '1.0'},
        events: { onLoad: onLoad, onError: xaml_error }});

  </script>
</div>
 
  
]]></Content>
</Module>

