document.addEventListener('DOMContentLoaded', ()=>{
   const pos = {
       x: 5,
       y: 10,
       d: 0,
   };

   const pan = {
       x: 0,
       y: 0
   };

   const labels = document.getElementById('labels');
   const txtBox = document.getElementById('txtBox');
   const data= document.getElementById('data');
   const importBtn = document.getElementById('importBtn');
   const can = document.getElementById('can');
   const ctx = can.getContext("2d");

   ctx.translate(0.5,0.5);
   ctx.imageSmoothingEnabled= false;

   const coffset = {
       x: can.getBoundingClientRect().left,
       y: can.getBoundingClientRect().top
   };

   let doorStyle=false;
   let chromaBg=false;

   let graph = [{"t":"seen","x":10,"y":5},{"t":"lvlup","x":10,"y":5},{"t":"seen","x":10,"y":6},{"t":"seen","x":10,"y":7},{"t":"seen","x":10,"y":9},{"t":"seen","x":11,"y":9},{"t":"seen","x":12,"y":9},{"t":"seen","x":12,"y":10},{"t":"seen","x":12,"y":11},{"t":"lvldn","x":12,"y":11},{"t":"seen","x":12,"y":7},{"t":"seen","x":12,"y":6},{"t":"seen","x":12,"y":5},{"t":"seen","x":13,"y":7},{"t":"seen","x":14,"y":7},{"t":"seen","x":14,"y":6},{"t":"seen","x":14,"y":5},{"t":"seen","x":15,"y":5},{"t":"seen","x":16,"y":5},{"t":"seen","x":17,"y":5},{"t":"seen","x":18,"y":5},{"t":"seen","x":12,"y":12},{"t":"seen","x":12,"y":13},{"t":"seen","x":13,"y":13},{"t":"seen","x":14,"y":13},{"t":"seen","x":16,"y":13},{"t":"seen","x":17,"y":13},{"t":"seen","x":18,"y":13},{"t":"seen","x":16,"y":12},{"t":"seen","x":16,"y":11},{"t":"seen","x":16,"y":10},{"t":"seen","x":16,"y":9},{"t":"seen","x":15,"y":9},{"t":"seen","x":14,"y":9},{"t":"seen","x":14,"y":10},{"t":"seen","x":14,"y":11},{"t":"seen","x":17,"y":9},{"t":"seen","x":18,"y":9},{"t":"seen","x":18,"y":8},{"t":"seen","x":18,"y":7},{"t":"seen","x":18,"y":11},{"t":"seen","x":18,"y":12},{"t":"seen","x":16,"y":7},{"t":"seen","x":14,"y":21},{"t":"lvlup","x":14,"y":21},{"t":"seen","x":13,"y":21},{"t":"half","x":13,"y":22},{"t":"seen","x":12,"y":21},{"t":"half","x":11,"y":22},{"t":"seen","x":11,"y":21},{"t":"seen","x":15,"y":21},{"t":"seen","x":16,"y":21},{"t":"fence","d":"v","x":17,"y":21},{"t":"seen","x":18,"y":21},{"t":"half","x":18,"y":22},{"t":"seen","x":19,"y":21},{"t":"seen","x":20,"y":21},{"t":"half","x":20,"y":20},{"t":"seen","x":16,"y":20},{"t":"seen","x":16,"y":19},{"t":"txt","v":"Mines of Mt. Drash","x":10,"y":3},{"t":"txt","v":"Level 1","x":13,"y":8},{"t":"txt","v":"Level 2","x":14,"y":22},{"t":"door","d":"h","x":16,"y":22,"hidden":false},{"t":"door","d":"h","x":18,"y":10,"hidden":false},{"t":"door","d":"v","x":15,"y":11,"hidden":false},{"t":"door","d":"h","x":18,"y":6,"hidden":true},{"t":"door","d":"h","x":16,"y":6,"hidden":false},{"t":"door","d":"v","x":13,"y":11,"hidden":false},{"t":"door","d":"h","x":12,"y":8,"hidden":false},{"t":"door","d":"h","x":10,"y":8,"hidden":true},{"t":"door","d":"v","x":11,"y":5,"hidden":false},{"t":"door","d":"v","x":13,"y":9,"hidden":false},{"t":"door","d":"v","x":15,"y":7,"hidden":false},{"t":"door","d":"v","x":15,"y":13,"hidden":false},{"t":"door","d":"h","x":16,"y":8,"hidden":false}];

   function draw() {
       ctx.save();
       ctx.clearRect(0,0, can.width, can.height);
       if(chromaBg) {
           ctx.rect(0,0, can.width, can.height);
           ctx.fillStyle = "#00ffff";
           ctx.fill();
           ctx.fillStyle="black";

       }
       ctx.transform(1, 0, 0, 1, pan.x*64, pan.y*64);

       // Draw stuff from graph
       labels.innerHTML='';
       graph.forEach( item=>{
           drawFunc[item.t](item);
           if(item.t === 'txt') {
               addLabel(item);
           }
       });
       // Draw cursor
       ctx.beginPath();
       ctx.arc( pos.x*32, pos.y*32, 10,0,  2*Math.PI);
       ctx.fillStyle = 'rgba(255,255,0,0.5)';
       ctx.fill();
       ctx.stroke();
       ctx.fillStyle = "red";

       ctx.beginPath();
       switch(pos.d) {
           case 0:
               ctx.arc(pos.x*32, pos.y*32-5 ,3, 0, 2*Math.PI);
               break;
           case 1:
               ctx.arc(pos.x*32+5, pos.y*32, 3, 0, 2*Math.PI);
               break;
           case 2:
               ctx.arc(pos.x*32, pos.y*32+5, 3, 0, 2*Math.PI);
               break;
           case 3:
               ctx.arc(pos.x*32-5, pos.y*32, 3, 0, 2*Math.PI);
               break;
       }
       ctx.fill();

       ctx.restore();
       data.value = JSON.stringify(graph, null, 4);
   }

   function addLabel(item) {
       const link = document.createElement('a');
       const br = document.createElement('br');
       const linkTxt = document.createTextNode(item.v);
       link.appendChild(linkTxt);
       link.title='Show '+item.v;
       link.onclick=panTo.bind(null, item);
       link.href='#';
       labels.appendChild(link);
       labels.appendChild(br);
   }


   function panTo(item) {
       pan.x = -(item.x/2);
       pan.y = -(item.y/2);
       pan.x += 4;
       pan.y += 4;
       draw();
   }

   const drawFunc = {
       seen: drawSeen,
       half: drawHalfSeen,
       lvlup: drawLvlUp,
       lvldn: drawLvlDown,
       door: drawDoor,
       fence: drawFence,
       txt: drawTxt,
   };

   function drawTxt(item) {
       ctx.fillStyle = "green";
       ctx.font = "16px Arial";
       ctx.fillText(item.v, item.x*32-10, item.y*32+6);
   }
   function drawSeen(item) {
       if(item.hidden) {
           drawHalfSeen(item);
           return;
       }

       ctx.beginPath();
       ctx.rect( item.x*32-16, item.y*32-16, 32, 32);
       ctx.fillStyle='#aaaaff';
       ctx.fill();

       //For each wall
       //Top:
       if(nothing(item.x, item.y-1)) {
           ctx.beginPath();
           ctx.moveTo( item.x*32-16, item.y*32-16 );
           ctx.lineTo( item.x*32+16, item.y*32-16);
           ctx.stroke();
       }
       //bottom:
       if(nothing(item.x, item.y+1)) {
           ctx.beginPath();
           ctx.moveTo( item.x*32-16, item.y*32+16 );
           ctx.lineTo( item.x*32+16, item.y*32+16);
           ctx.stroke();
       }
       //left
       if(nothing(item.x-1, item.y)) {
           ctx.beginPath();
           ctx.moveTo( item.x*32-16, item.y*32+16 );
           ctx.lineTo( item.x*32-16, item.y*32-16);
           ctx.stroke();
       }
       //right
       if(nothing(item.x+1, item.y)) {
           ctx.beginPath();
           ctx.moveTo( item.x*32+16, item.y*32+16 );
           ctx.lineTo( item.x*32+16, item.y*32-16);
           ctx.stroke();
       }
   }

   function nothing(x,y) {
       return !graph.some( item=> (item.x===x && item.y===y && item.t !== 'txt'));
   }

   function drawHalfSeen(item) {
       ctx.beginPath();
       ctx.rect( item.x*32-16, item.y*32-16, 32, 32);
       ctx.fillStyle='#aaaaaa';
       ctx.fill();

   }

   function drawLvlUp(item) {
       drawSeen(item);
       ctx.beginPath();
       ctx.moveTo( item.x*32 , item.y*32-9  ); // top
       ctx.lineTo( item.x*32+9 , item.y*32+9  ); // right
       ctx.lineTo( item.x*32-9 , item.y*32+9  ); // left
       ctx.closePath();
       ctx.fillStyle ='#348078';
       ctx.fill();
   }

   function drawLvlDown(item) {
       drawSeen(item);
       ctx.beginPath();
       ctx.moveTo( item.x*32 , item.y*32+9  ); // bottom
       ctx.lineTo( item.x*32+9 , item.y*32-9  ); // right
       ctx.lineTo( item.x*32-9 , item.y*32-9  ); // left
       ctx.closePath();
       ctx.fillStyle ='#348078';
       ctx.fill();
   }

   function drawFence(item) {
       drawSeen(item);

       ctx.beginPath();
       if(item.d === 'v') {
           ctx.moveTo( item.x*32, item.y*32 - 16);
           ctx.lineTo( item.x*32, item.y*32+16);
       } else {
           ctx.moveTo( item.x*32-16, item.y*32);
           ctx.lineTo( item.x*32+16, item.y*32);
       }
       ctx.strokeStyle="brown";
       ctx.stroke();
       ctx.strokeStyle="black";
   }

   function drawDoor(item) {

       drawSeen({x:item.x, y:item.y});
       ctx.beginPath();
       switch(item.d) {
           case 'h':
               if(doorStyle) {
                   ctx.moveTo( item.x*32-16, item.y*32-16)
                   ctx.lineTo( item.x*32+16, item.y*32-16);
                   ctx.moveTo( item.x*32-16, item.y*32+16)
                   ctx.lineTo( item.x*32+16, item.y*32+16);
                   ctx.stroke();
                   ctx.beginPath();
                   ctx.rect( item.x*32-8, item.y*32-18, 16, 5);
                   ctx.rect( item.x*32-8, item.y*32+14, 16, 5);
               } else {
                   ctx.moveTo( item.x*32-16, item.y*32)
                   ctx.lineTo( item.x*32+16, item.y*32);
                   ctx.stroke();
                   ctx.beginPath();
                   ctx.rect( item.x*32-8, item.y*32-2, 16, 5);
               }
               break;
           case 'v':
               if(doorStyle) {
                   ctx.moveTo( item.x*32+16, item.y*32+16)
                   ctx.lineTo( item.x*32+16, item.y*32-16);
                   ctx.moveTo( item.x*32-16, item.y*32+16)
                   ctx.lineTo( item.x*32-16, item.y*32-16);
                   ctx.stroke();
                   ctx.beginPath();
                   ctx.rect( item.x*32-18, item.y*32-8, 5, 16);
                   ctx.rect( item.x*32+14, item.y*32-8, 5, 16);
               } else {
                   ctx.moveTo( item.x*32, item.y*32+16)
                   ctx.lineTo( item.x*32, item.y*32-16);
                   ctx.stroke();
                   ctx.beginPath();
                   ctx.rect( item.x*32-2, item.y*32-8, 5, 16);
               }
               break;
       }

       if(item.hidden) {
           ctx.fillStyle = '#a86f32';
       } else {
           ctx.fillStyle = "#bebebe";
       }

       ctx.fill();
       ctx.stroke();


   }

   window.addEventListener('keydown', (e)=>{
       if(document.activeElement.tagName !== 'BODY') {
           return;
       }
       let prevent=true;
       switch(e.which) {
           case 38: // up
               pos.y--;
               pos.d=0;
               updatePanForCursor();
               break;
           case 40: // down
               pos.y++;
               pos.d=2;
               updatePanForCursor();
               break;
           case 37: // left
               pos.x--;
               pos.d=3;
               updatePanForCursor();
               break;
           case 39: // right
               pos.x++;
               pos.d=1;
               updatePanForCursor();
               break;
           case 32: // spacebar
               toggleCellSeen(1);
               break;
//            case 17: // Ctrl
               break;
           case 49: // 1: doors
               toggleCellSeen(2);
               break;
           case 50: // 2: half-seen
               toggleCellSeen(1,true);
               break;
           case 51: // 3:  lvl up
               toggleCellSeen(4);
               break;
           case 52:
               toggleCellSeen(5);
               break;
           case 16: // shift
               toggleHidden();
               break;
           case 53: // 5: vfence
               toggleCellSeen(6);
               break;
           case 54: // 6:
               break;
           case 104: // keypad up: pan
               pan.y++;
               break;
           case 98: // keypad down
           case 101: // keypad down
               pan.y--;
               break;
           case 100: // left
               pan.x++;
               break;
           case 102:
               pan.x--;
               break;
           case 13: // Enter = text
               toggleCellSeen(8);
               break;
           case 82: // r = rotate
               pos.d++;
               if(pos.d===4) pos.d=0;
               break;
           case 69: // e = rotate the other way
               pos.d--;
               if(pos.d <0) pos.d =3;
               break;
           case 68: // d = doorStyle
               doorStyle = !doorStyle;
               break;
           case 67: // c = toggle chroma bg
               chromaBg = !chromaBg;
               break;
           default:
               console.log('unhandled keycode: '+e.which);
               prevent=false;
       }

       if(prevent) {
           e.preventDefault();
       }


       draw();

   });

   function updatePanForCursor() {
       if(pos.x*32 + pan.x*64 > 512) {
           pan.x--;
       }
       if(pos.x*32 + pan.x*64 < 0) {
           pan.x++;
       }
       if(pos.y*32 + pan.y*64 > 512) {
           pan.y--;
       }
       if(pos.y*32 + pan.y*64 < 0) {
           pan.y++;
       }
   }

   function toggleHidden() {
       graph.forEach( item=> {
           if(item.x === pos.x && item.y === pos.y) {
               item.hidden=!item.hidden;
           }
       });
   }

   function toggleCellSeen(type, hidden) {

       //Find any cells at cursor pos
       let found=false;
       graph = graph.filter( item =>{
           if(item.x === pos.x && item.y === pos.y ) {
               found=true;
               return false;
           }
           return true;
       });

       if(!found) {
           switch(type) {
               case 1:
                   graph.push( { t: 'seen', x: pos.x, y: pos.y, hidden:hidden});
                   break;
               case 2: // doors
                   addInline('door');
                   break;
               case 4: // level up
                   graph.push( { t:'lvlup', x: pos.x, y: pos.y } );
                   break;
               case 5: // level down
                   graph.push( { t:'lvldn', x: pos.x, y: pos.y } );
                   break;
               case 6: // fence
                   addInline('fence');
                   break;
               case 8: //text
                   graph.push( { t: 'txt', v: txtBox.value, x: pos.x, y: pos.y });
                   break;
           }
       }

       // Sort the array, doors last!
       graph = graph.sort( (a,b)=>{
           if(a.t === 'door') {
               return 1;
           }
           return -1;
       });



   }

   function addInline(t) {
       if( !nothing(pos.x, pos.y-1) || !nothing(pos.x, pos.y+1))
       {
                   graph.push( { t, d:'h', x: pos.x, y: pos.y } );
       } else if(!nothing(pos.x-1, pos.y) || !nothing(pos.x+1, pos.y) ) {
                   graph.push( { t, d:'v', x: pos.x, y: pos.y } );
       }
   }


   can.addEventListener('click', (e)=>{
       const x = e.layerX - coffset.x;
       const y = e.layerY - coffset.y;
       pos.x = Math.round( ((x - pan.x*64)/32) );
       pos.y = Math.round( ((y - pan.y*64)/32) );
       draw();
   });

   importBtn.addEventListener('click', ()=> {
       try {
           graph = JSON.parse(data.value);
       } catch(ignored) {
           graph = [];
       }

       draw();
   });

   draw();
});