/*
 * Parse .ipuz crossword files.
 */
function Ipuz(data) {

  this.FLAGS = {
    INCORRECT_ONCE: 0x10,
    INCORRECT: 0x20,
    REVEALED: 0x40,
    CIRCLED: 0x80,
    HIDDEN: 0x100,
    SHADED: 0x200,
  };

  this.headers = [];  // list of [header, value]
  this.grid = [];     // [y][x] 2-dim array
  this.flags = [];     // [y][x] 2-dim array
  this.clues = [];    // list of [[direction, num], clue, answer]
  this.notes = "";
  this.number_index = [];
  this.rebus_key = {};
  this.width = 0;
  this.height = 0;
  this.BLOCK = "#";

  var self = this;

  this.parseIpuz = function(json) {

    const ipuz = JSON.parse(json);

    const dimensions = ipuz.dimensions;
    const width = parseInt(dimensions.width);
    const height = parseInt(dimensions.height);

    self.width = width;
    self.height = height;

    const puzzle = ipuz.puzzle;
    const solution = ipuz.solution;
    const acrossClues = ipuz.clues.Across;
    const downClues = ipuz.clues.Down;

    for (var i = 0; i < height; i++) {
        var flagsline = Array(width).fill(0);
        var gridline = Array(width);

        var puzzleRow = puzzle[i];
        var solutionRow = solution[i];

        for (var j = 0; j < width; j++) {
            gridline[j] = solutionRow[j] || " ";
            if (puzzleRow[j] === this.BLOCK) {
                gridline[j] = this.BLOCK;
            }

            if (puzzleRow[j] == null) {
                flagsline[j] |= self.FLAGS.HIDDEN;
            }
            if (puzzleRow[j].hasOwnProperty('style')) {
                if (puzzleRow[j]['style'].get('shapebg') === 'circle') {
                    flagsline[j] |= self.FLAGS.CIRCLED;
                }
            }
            const cell = parseInt(puzzleRow[j].cell || puzzleRow[j]);
            if (cell > 0) {
                self.number_index[cell] = [j, i];
            }
        }

        self.grid.push(gridline);
        self.flags.push(flagsline);
    }

    for (var i = 0; i < acrossClues.length; i++) {
        self.addClue('A', acrossClues[i]);
    }

    for (var i = 0; i < downClues.length; i++) {
        self.addClue('D', downClues[i]);
    }
  }

  this.addClue = function(direction, numClue) {
    var num;
    var clue;

    if (numClue.hasOwnProperty('number')) {
        num = numClue.number;
        clue = numClue.clue;
    } else {
        num = parseInt(numClue[0]);
        clue = numClue[1];
    }

    const xy = self.number_index[num];
    self.clues.push([[direction, num], clue,
                    self.getAnswer(direction, xy[0], xy[1])]);
  }

  this.getAnswer = function(direction, x, y) {
    var xinc = direction === 'A' ? 1 : 0;
    var yinc = direction === 'D' ? 1 : 0;

    var str = '';
    while (y < self.height && x < self.width &&
           self.grid[y][x] !== this.BLOCK &&
           !(self.flags[y][x] & self.FLAGS.HIDDEN)) {
      str += self.grid[y][x];
      y += yinc;
      x += xinc;
    }
    return str;
  }

  self.parseIpuz(data);
}

if (typeof(module) !== "undefined") {
  module.exports = Ipuz;
}

@@ -536,28 +536,8 @@
 %22;%0A%0A
-  var self = this;%0A%0A
   th
@@ -744,20 +744,20 @@
 );%0A%0A    
-self
+this
 .width =
@@ -768,20 +768,20 @@
 th;%0A    
-self
+this
 .height 
@@ -942,16 +942,108 @@
 .Down;%0A%0A
+    this.headers = %5B%0A        %5B'Author', ipuz.author%5D,%0A        %5B'Title', ipuz.title%5D%0A    %5D;%0A%0A
     for 
@@ -1495,28 +1495,28 @@
 sline%5Bj%5D %7C= 
-self
+this
 .FLAGS.HIDDE
@@ -1697,20 +1697,20 @@
 e%5Bj%5D %7C= 
-self
+this
 .FLAGS.C
@@ -1863,20 +1863,20 @@
         
-self
+this
 .number_
@@ -1926,28 +1926,28 @@
  %7D%0A%0A        
-self
+this
 .grid.push(g
@@ -1964,20 +1964,20 @@
         
-self
+this
 .flags.p
@@ -2050,36 +2050,36 @@
  i++) %7B%0A        
-self
+this
 .addClue('A', ac
@@ -2157,20 +2157,20 @@
         
-self
+this
 .addClue
@@ -2478,20 +2478,20 @@
 st xy = 
-self
+this
 .number_
@@ -2506,20 +2506,20 @@
 m%5D;%0A    
-self
+this
 .clues.p
@@ -2567,20 +2567,20 @@
         
-self
+this
 .getAnsw
@@ -2780,20 +2780,20 @@
 le (y %3C 
-self
+this
 .height 
@@ -2799,20 +2799,20 @@
  && x %3C 
-self
+this
 .width &
@@ -2824,20 +2824,20 @@
         
-self
+this
 .grid%5By%5D
@@ -2871,20 +2871,20 @@
       !(
-self
+this
 .flags%5By
@@ -2890,20 +2890,20 @@
 y%5D%5Bx%5D & 
-self
+this
 .FLAGS.H
@@ -2925,20 +2925,20 @@
  str += 
-self
+this
 .grid%5By%5D
@@ -3009,12 +3009,12 @@
 %0A%0A  
-self
+this
 .par

Add author/title fields for ipuz & drop self/this cargo cult