<%
  words_with_clues = {
    'Andrew':        'the man who loves you the most',
    'Amy':           'the best wife in the world',
    'Amsterdam':     'our first stop in europe',
    'England':       'our second country in europe',
    'Italy':         'our last country in europe',
    'Vesuvius':      'birthday volcano',
    'Bethany':       'your maid of honor',
    'Clayton':       'the bestest of men (for a wedding)',
    'honeymoon':     'Niagara Falls',
    'rednovalabs':   'KC office of love',
    'Lucy':          'our little wocky slush',
    'Dimitri':       'our little fuzzy bitch boy',
    'humming':       'type of porch-nesting bird',
    'raytown':       "the city of Benetti's",
    'flanders':      "sad valentine's dog",
    'amycakes':      "Amy's delicious Valentine's dessert",
    'mashed':        'the best form of potatoes',
    'Ireland':       'the european country we biked the most in',
    'sunflower':     "Amy's favorite flower",
    "mountain":      'engaged on top of a _____',
    'Norway':        'the best country to get engaged in',
    'Joplin':        'the city Dimitri came from',
    'Independence':  'the city of our wedding venue',
    'rain':          'what fell from the sky while we got married',
    'Cancun':        "bachelor party destination",
    'Jumeirah':      "the Burj Al Arab is next to _____ Beach",
    'marriage':      'this bwings us togeder, spelled correctly',

    # movies
    'delivery':      "Kiki's _____ Service",
    'neighbor':      'My _____ Totoro',
    'castle':        "Howl's Moving _____",

    # Movies: Princess Bride
    'Rugen':         "This Count killed Inigo's father",
    'never':         "when to go against a Sicilian when death is on the line",
    'iocane':        'powder the Dread Pirate Roberts cultivated an immunity for',
    'Buttercup':     'the name of the eponymous Princess Bride',
    'Inconceivable': "Vizzini's oft-misused word that Inigo questions",
    'wife':          "'I'm not a witch, I'm your ______!'",

    # Movies: Disney

    # TV: The Office
    'Mose':          "Dwight's cousin at Schute Farms",
    'Foreman':       "Michael burned his foot on this George ______ grill",
    'refrigeration': 'Bob Vance of Vance _____',
    'Meredith':      'Michael hits her with a car',
    'Colorado':      'the state Michael and Holly eventually move away to',
    'Sprinkles':     "Angela's cold, dead cat, thanks to Dwight",
    'Hunter':        "Jan Levinson's musically-talented assistant",
    'Pete':          "Plop's actual name in The Office",
    'pita':          "Ryan caused the fire while heating up this cheesy bread",
    'Treble':        "Andy's a capella group from Cornell: Here Comes _____",
    'bacon':         "Michael Scott loves to wake up to the smell of this meat",
    "Scrantonicity": "Kevin Malone's band",
    "Electric":      "Scranton's nickname is The _____ City",
    "lithium":       "what kind of batteries do Scott's Tots get instead of tuition?",
    "Dementors":     "the worst part of prison, according to Prison Mike",
    "jello":         "edible substance that Jim puts office supplies in",
    "MISSsterious":  "women's suit brand unknowingly donned by Michael Scott",
    "Kelly":         "who needs to access their 'uncrazy' side?",
    "ignorant":      "what kind of slut is Dwight?",
    "superstitious": "Michael Scott is a little stitious, but he's not _____",
    "both":          "Would Michael Scott rather be feared or loved?",
    "Creed":         "The Office coworker that tries to set Jim up with his daughter",
    "king":          "the level of lizard royalty Robert California claims to be",
    "rabies":        "what disease does Michael Scott organize a fun run for?",
    "Susan":         "Gabe Lewis's middle name in The Office",
    "broccoli":      "what vegetable does Michael Scott force-feed Kevin?",
    "Drummer":       "Angela Kinsley's favorite song is about a boy with this occupation",
    "crossword":     "What kind of puzzle is Stanley almost always seen doing on The Office?",

    # TV: 30 Rock
    'Rockefeller':   'The "Rock" in 30 Rock is short for this',
    'Oprah':         'Liz Lemon mistakes a 12-year-old girl for this celebrity',
    'Greenzo':       "David Schwimmer's eco-friendly mascot on 30 Rock",
    'Jenna':         'who would literally kill herself if Jack hired another blonde woman?',

    # TV: P&R
    'recreation':    'Parks and ______',
    'Gryzzl':        'this hip startup is trying to buy the Newport land',
    'Janet':         "the aristrocratic Ms. Snakehole's first name",
    'Barkley':       "Bobby Newport's campign lobbyist's last name",
    'Batman':        "Ben's Treat-yo-self costume",
    "Indiana":       "Pawnee's state",
    "Bloosh":        "Annabel Porter's internet lifestyle magazine",
    'Hogwarts':      "what Andy mistakes Buckingham Palace for",
    'Tammy':         'the strangely irresistable name for Ron Swanson',

    # Books
    'Monte':         'The Count of _____ Cristo',
    'revenge':       'what Edmon Dantes wants most',
    'Anne':          'the youngest Bronte sister',
    'secrets':       'Harry Potter and the Chamber of _____',
    'GGM':           'a master of literary time travel',
    'Goldfinch':     'The _____, starring Theodore Decker',
    'Bassoon':       'Raine Wilson is The _____ King',
    'Rye':           'J.D. Salinger says the Catcher is in here',
    'Kite':          "what Amir runs to fetch in Afghanistan",
    'death':         'What Gabriel Garcia Marquez chronicled and foretold',
    'Cholera':       'Love in the Time of _____',
    'one':           'how many hundred years of solitude?',
    'Alchemist':     'the titular wiseman to Santigo, a young Spanish shepard',
    'phantom':       'the kind of toolbooth that can suddenly appear',
    'three':         'how many musketeers?',
    'innocence':     "the age Edith Wharton is most concerned about",
    "Narnia":        "Lucy, Edmund, Peter, and Susan visit here",
    'Caspian':       "The Dawn Treader's captain",
    'unusual':       'ROUS: Rodents of _____ Size',
    'Florin':        'in what fictional country does The Princess Bride take place?',

    # Music
    'ironic':        'like rain on your wedding day',
    'toro':          '___ y Moi',
    'Chazwick':      "Toro y Moi's real first name",
    'JamesMurphy':   "he's spinning at Chazwick's house",
    'Daft':          "the punk playing at James Murphy's house",

    # memes
    'tiktok':        'the successor to vine',
    'roadworkahead': 'yeah, i sure hope it do'
  }

  selected_words = words_with_clues.to_a.sample(15).to_h
%>

<style>
  html{
    height:100%;
  }
  body{
    height:100%;
    min-width: 400px;
    margin:0;
    
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }

  .container{
    position: absolute;
    bottom: 0; top: 0; left: 0; right: 0;
    text-align: center;
  }
  .center{
    margin: 0 auto;
  }

  .btn{
    margin: 8px 4px 0;
    width: 172px;
    height: 28px;
  }

  .line{  
    height: 2em;
  }
  .word, .clue{
    display: inline-block;
    height: 1.5em;  
    padding: 0 5px;
  }
  .word{
    text-align: right;  
    width: 100px;
  }
  .clue{
    width: 500px;
    padding: 0.5em;
  }
  .clue:hover {
    background: pink;
  }

  .crossword{
    display: block;  
    background-color: rgb(32,32,32);  
  }
  .square{  
    margin: 0 1px 1px 0;
    display: inline-block;
    font: 24px Calibri;
    width: 1.25em;
    height: 1.25em;
    line-height: 1.25em;
    vertical-align: middle;
    
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }
  .letter{
    background-color: rgb(255,255,255);
    
    -webkit-touch-callout: text;
    -webkit-user-select: text;
    -khtml-user-select: text;
    -moz-user-select: text;
    -ms-user-select: text;
    user-select: text;
  }
  .char:focus{
    -webkit-box-shadow: 0 0 0 1px yellow;
    -moz-box-shadow: 0 0 0 1px yellow;
    box-shadow: inset 0 0 0 1px yellow;  
    background: pink;
  }
  .char {
    font-size:24px;
    text-transform: uppercase;
    outline: 0;
    border: 0;
    padding: 0;
    margin: -1px 0 0 -1px;
    width: 1.35em;
    height: 1.35em;
    text-align: center;
    background: none; 
  } 

  .hide{
    visibility: hidden;
  }

  .clueReadOnly
  {
    border: 0 ;
    outline: 0;
    color:#303030 !important;
    background:none;
  }
  .strikethrough {
    text-decoration: line-through;
  }
</style>

<div class="container">
  <button class="btn" id="btnCreate">Solve</button>
  <br/><br/>  

  <div class="center crossword" id="crossword"></div><br/>

  <div class="center">

    <% selected_words.each do |word, clue| %>
      <div class="line">
        <input class="word" type="text" value="<%= word %>" />
        <input class="clue" value="<%= clue %>" />
      </div>
    <% end %>

  </div>
</div>

<script type="text/javascript">
  //---------------------------------//
  //   GLOBAL VARIABLES              //
  //---------------------------------//

  var board, wordArr, wordBank, wordsActive, mode;

  var Bounds = {  
    top:0, right:0, bottom:0, left:0,

    Update:function(x,y){
      this.top = Math.min(y,this.top);
      this.right = Math.max(x,this.right);
      this.bottom = Math.max(y,this.bottom);
      this.left = Math.min(x,this.left);
    },
    
    Clean:function(){
      this.top = 999;
      this.right = 0;
      this.bottom = 0;    
      this.left = 999;
    }
  };


  //---------------------------------//
  //   MAIN                          //
  //---------------------------------//

  function Play(){
    var letterArr = document.getElementsByClassName('letter');
    
    for(var i = 0; i < letterArr.length; i++){
      letterArr[i].innerHTML = "<input class='char' type='text' maxlength='1'></input>";
    }
    
    mode = 0;
    ToggleInputBoxes(false);
  }


  function Create(){
    if (mode === 0){
      ToggleInputBoxes(true);
      document.getElementById("crossword").innerHTML = BoardToHtml(" ");
      document.getElementById('btnCreate').innerText = 'New crossword';
      mode = 1;
    }
    else{  
      GetWordsFromInput();

      for(var i = 0, isSuccess=false; i < 10 && !isSuccess; i++){
        CleanVars();
        isSuccess = PopulateBoard();
      }

      document.getElementById("crossword").innerHTML = 
        (isSuccess) ? BoardToHtml(" ") : "Failed to find crossword." ;
      document.getElementById('btnCreate').innerText = 'Solve';

      Play();
    }
  }


  function ToggleInputBoxes(active){
    var w=document.getElementsByClassName('word'),
        d=document.getElementsByClassName('clue');
    
    for(var i=0;i<w.length; i++){
      if(active===true){
        RemoveClass(w[i], 'hide');
        RemoveClass(d[i], 'clueReadOnly');
        d[i].disabled = '';
      }
      else{
        AddClass(w[i], 'hide');
        AddClass(d[i], 'clueReadOnly');
        d[i].disabled = 'readonly';
      }
    }
  }


  function GetWordsFromInput(){
    wordArr = [];  
    for(var i=0,val,w=document.getElementsByClassName("word");i<w.length;i++){
      val = w[i].value.toUpperCase();
      if (val !== null && val.length > 1){wordArr.push(val);}
    }
  }


  function CleanVars(){
    Bounds.Clean();
    wordBank = [];
    wordsActive = [];
    board = [];
    
    for(var i = 0; i < 32; i++){
      board.push([]);
      for(var j = 0; j < 32; j++){
        board[i].push(null);
      }
    }
  }


  function PopulateBoard(){
    PrepareBoard();
    
    for(var i=0,isOk=true,len=wordBank.length; i<len && isOk; i++){
      isOk = AddWordToBoard();
    }  
    return isOk;
  }


  function PrepareBoard(){
    wordBank=[];
    
    for(var i = 0, len = wordArr.length; i < len; i++){
      wordBank.push(new WordObj(wordArr[i]));
    }
    
    for(i = 0; i < wordBank.length; i++){
      for(var j = 0, wA=wordBank[i]; j<wA.char.length; j++){
        for(var k = 0, cA=wA.char[j]; k<wordBank.length; k++){
          for(var l = 0,wB=wordBank[k]; k!==i && l<wB.char.length; l++){
            wA.totalMatches += (cA === wB.char[l])?1:0;
          }
        }
      }
    }  
  }


  // TODO: Clean this guy up
  function AddWordToBoard(){
    var i, len, curIndex, curWord, curChar, curMatch, testWord, testChar, 
        minMatchDiff = 9999, curMatchDiff;  

    if(wordsActive.length < 1){
      curIndex = 0;
      for(i = 0, len = wordBank.length; i < len; i++){
        if (wordBank[i].totalMatches < wordBank[curIndex].totalMatches){
          curIndex = i;
        }
      }
      wordBank[curIndex].successfulMatches = [{x:12,y:12,dir:0}];
    }
    else{  
      curIndex = -1;
      
      for(i = 0, len = wordBank.length; i < len; i++){
        curWord = wordBank[i];
        curWord.effectiveMatches = 0;
        curWord.successfulMatches = [];
        for(var j = 0, lenJ = curWord.char.length; j < lenJ; j++){
          curChar = curWord.char[j];
          for (var k = 0, lenK = wordsActive.length; k < lenK; k++){
            testWord = wordsActive[k];
            for (var l = 0, lenL = testWord.char.length; l < lenL; l++){
              testChar = testWord.char[l];            
              if (curChar === testChar){
                curWord.effectiveMatches++;
                
                var curCross = {x:testWord.x,y:testWord.y,dir:0};              
                if(testWord.dir === 0){                
                  curCross.dir = 1;
                  curCross.x += l;
                  curCross.y -= j;
                } 
                else{
                  curCross.dir = 0;
                  curCross.y += l;
                  curCross.x -= j;
                }
                
                var isMatch = true;
                
                for(var m = -1, lenM = curWord.char.length + 1; m < lenM; m++){
                  var crossVal = [];
                  if (m !== j){
                    if (curCross.dir === 0){
                      var xIndex = curCross.x + m;
                      
                      if (xIndex < 0 || xIndex >= board.length){
                        isMatch = false;
                        break;
                      }
                      
                      crossVal.push(board[xIndex][curCross.y]);
                      crossVal.push(board[xIndex][curCross.y + 1]);
                      crossVal.push(board[xIndex][curCross.y - 1]);
                    }
                    else{
                      var yIndex = curCross.y + m;
                      
                      if (yIndex < 0 || yIndex >= board[curCross.x].length){
                        isMatch = false;
                        break;
                      }
                      
                      crossVal.push(board[curCross.x][yIndex]);
                      crossVal.push(board[curCross.x + 1][yIndex]);
                      crossVal.push(board[curCross.x - 1][yIndex]);
                    }

                    if(m > -1 && m < lenM-1){
                      if (crossVal[0] !== curWord.char[m]){
                        if (crossVal[0] !== null){
                          isMatch = false;                  
                          break;
                        }
                        else if (crossVal[1] !== null){
                          isMatch = false;
                          break;
                        }
                        else if (crossVal[2] !== null){
                          isMatch = false;                  
                          break;
                        }
                      }
                    }
                    else if (crossVal[0] !== null){
                      isMatch = false;                  
                      break;
                    }
                  }
                }
                
                if (isMatch === true){                
                  curWord.successfulMatches.push(curCross);
                }
              }
            }
          }
        }
        
        curMatchDiff = curWord.totalMatches - curWord.effectiveMatches;
        
        if (curMatchDiff<minMatchDiff && curWord.successfulMatches.length>0){
          curMatchDiff = minMatchDiff;
          curIndex = i;
        }
        else if (curMatchDiff <= 0){
          return false;
        }
      }
    }
    
    if (curIndex === -1){
      return false;
    }
      
    var spliced = wordBank.splice(curIndex, 1);
    wordsActive.push(spliced[0]);
    
    var pushIndex = wordsActive.length - 1,
        rand = Math.random(),
        matchArr = wordsActive[pushIndex].successfulMatches,
        matchIndex = Math.floor(rand * matchArr.length),  
        matchData = matchArr[matchIndex];
    
    wordsActive[pushIndex].x = matchData.x;
    wordsActive[pushIndex].y = matchData.y;
    wordsActive[pushIndex].dir = matchData.dir;
    
    for(i = 0, len = wordsActive[pushIndex].char.length; i < len; i++){
      var xIndex = matchData.x,
          yIndex = matchData.y;
      
      if (matchData.dir === 0){
        xIndex += i;    
        board[xIndex][yIndex] = wordsActive[pushIndex].char[i];
      }
      else{
        yIndex += i;  
        board[xIndex][yIndex] = wordsActive[pushIndex].char[i];
      }
      
      Bounds.Update(xIndex,yIndex);
    }
      
    return true;
  }


  function BoardToHtml(blank){
    for(var i=Bounds.top-1, str=""; i<Bounds.bottom+2; i++){
      str+="<div class='row'>";
      for(var j=Bounds.left-1; j<Bounds.right+2; j++){
        str += BoardCharToElement(board[j][i]);
      }
      str += "</div>";
    }
    return str;
  }


  function BoardCharToElement(c){
    var arr=(c)?['square','letter']:['square'];
    return EleStr('div',[{a:'class',v:arr}],c);
  }



  //---------------------------------//
  //   OBJECT DEFINITIONS            //
  //---------------------------------//

  function WordObj(stringValue){
    this.string = stringValue;
    this.char = stringValue.split("");
    this.totalMatches = 0;
    this.effectiveMatches = 0;
    this.successfulMatches = [];  
  }


  //---------------------------------//
  //   EVENTS                        //
  //---------------------------------//

  function RegisterEvents(){
    document.getElementById("crossword").onfocus = function (){ 
      return false; }
    document.getElementById("btnCreate").addEventListener('click', Create, false);
  }
  RegisterEvents();


  //---------------------------------//
  //   HELPER FUNCTIONS              //
  //---------------------------------//

  function EleStr(e,c,h){
    h = (h)?h:"";
    for(var i=0,s="<"+e+" "; i<c.length; i++){
      s+=c[i].a+ "='"+ArrayToString(c[i].v," ")+"' ";    
    }
    return (s+">"+h+"</"+e+">");
  }

  function toggle_strike_through(self) {
    console.log('toggling');
    console.log(this);
    console.log(self);
  }

  function ArrayToString(a,s){
    if(a===null||a.length<1)return "";
    if(s===null)s=",";
    for(var r=a[0],i=1;i<a.length;i++){r+=s+a[i];}
    return r;
  }

  function AddClass(ele,classStr){
    ele.className = ele.className.replaceAll(' '+classStr,'')+' '+classStr;
  }

  function RemoveClass(ele,classStr){
    ele.className = ele.className.replaceAll(' '+classStr,'');
  }

  function ToggleClass(ele,classStr){
    var str = ele.className.replaceAll(' '+classStr,'');
    ele.className = (str.length===ele.className.length)?str+' '+classStr:str;
  }

  String.prototype.replaceAll = function (replaceThis, withThis) {
    var re = new RegExp(replaceThis,"g"); 
    return this.replace(re, withThis);
  };


  //---------------------------------//
  //   INITIAL LOAD                  //
  //---------------------------------//

  Create();
</script>

<script>
  $(document).ready(function () {
    $('.line').click(function () {
      $(this).find('.clue').toggleClass('strikethrough');
    });
  })
</script>