// Change ITEMS for amount of bars.
const ITEMS = 50;

// Grab canvas and context.
let canvas_org = document.getElementById('originalList');
let canvas_count = document.getElementById('countList');
let canvas_final = document.getElementById('finalList');

let context_org = canvas_org.getContext('2d');
let context_count = canvas_count.getContext('2d');
let context_final = canvas_final.getContext('2d');

let pad0 = document.getElementById('pad0');
let pad1 = document.getElementById('pad1');
let pad2 = document.getElementById('pad2');

// Declare array to be ITEMS long.
let list = new Array(ITEMS);
let comparison_count = 0;
let swap_count = 0;

// Flags used to determine if bg or bars need redrawn.
let updateBG = true;
let updateBars = true;

// Setup event listeners for window.
function setupCanvas() {
    // Setup event listeners for load and window resize.
  window.addEventListener('load', canvasResize);
  window.addEventListener('resize', canvasResize);
}

// Initializes the list of 100 random numbers.
function initList() {
  for (let i = 0; i < ITEMS; i++)
      list[i] = Math.round(Math.random() * 100);
    comparison_count = 0;
    swap_count = 0;
}

// This function grabs the width and height of the window
// and resizes the canvas  in the event of loading or resizing.
function canvasResize() {
  canvas_org.width = window.innerWidth;
  canvas_org.height = window.innerHeight/4;
  canvas_count.width = window.innerWidth;
  canvas_count.height = window.innerHeight/4;
  canvas_final.width = window.innerWidth;
  canvas_final.height = window.innerHeight/4;
  
  pad0.setAttribute("style", "height: " + window.innerHeight/12);
  pad0.innerText = "Original " + ITEMS + " numbers:";
  pad0.style.fontSize = window.innerHeight/16;
  
  pad1.setAttribute("style", "height: " + window.innerHeight/12);
  pad1.innerText = "Count Section:";
  pad1.style.fontSize = window.innerHeight/16;
  
  pad2.setAttribute("style", "height: " + window.innerHeight/12);
  pad2.innerText = "Final List:";
  pad2.style.fontSize = window.innerHeight/16;
  
  updateBG = true;
  updateBars = true;
}

// Finds the largest number in the list.
function max() {
  let maximum = list[0];
  for (let i = 1; i < ITEMS; i++)
    maximum = list[i] > maximum ? list[i] : maximum;
  return maximum;
}

// Comparing indicators to draw in different colors.
// cmp1 and cmp2 are two indices being compared, make them
// negative to mean a switch is happening
let cmp1 = 0;
let cmp2 = 0;

// Plot each index of list[].
function plotBars() {
  let length = list.length;
  let barWidth = canvas_org.width / length;
  let barScale = canvas_org.height / max();
  for (let i = 0; i < ITEMS; i++) {
    let x = i * barWidth;
    let h = list[i] * barScale;
    let y = canvas_org.height - h;
    
    context_org.save();
    context_org.fillStyle = 'orange';
    context_org.fillRect(x+1, y, barWidth-2, h);
    context_org.restore();
  }
}

// Draws the black background.
function drawBackground() {

  context_org.save();
  context_org.fillStyle = 'black';
  context_org.fillRect(0, 0, canvas_org.width, canvas_org.height);

  // Pops most recently saved canvas state off stack.
  context_org.restore();


  context_count.save();
  context_count.fillStyle = 'black';
  context_count.fillRect(0, 0, canvas_count.width, canvas_count.height);

  // Pops most recently saved canvas state off stack.
  context_count.restore();


  context_final.save();
  context_final.fillStyle = 'black';
  context_final.fillRect(0, 0, canvas_final.width, canvas_final.height);

  // Pops most recently saved canvas state off stack.
  context_final.restore();


}

// These are some variables that flag and alter various parts 
// of the sort. You may need to add/remove/modify your own 
// depending on the  complexity of your sorting method.
let sortStarted = false;
let sortFinished = false;

// Delay between sorting simulations.
let restartDelay = 5000;

// Delay between comparasins.
let sortDelay = 100;
let sortIndex = 0;

// adapted from https://en.wikipedia.org/wiki/Comb_sort
let gap = ITEMS
let shrink = 1.3

// Sorting function. This example uses bubble sort.
function sortStart() {
  // Finished is used to mark when no swaps were done in a sort loop.
  // Think of it as finishing one sorting loop.
  let finished = false; // note - set to false except for when gap is 1

  // tmp is used as a temporary value when swapping.
  let tmp;
    
  // Flip the sortStarted flag.
  sortStarted = true;

    gap = Math.floor(gap / shrink)
    if (gap <= 1) {
	// for gap=1, keep track of if there were any swaps
	gap = 1
	finished = true
    }
    
  // setInterval() runs once every <sortDelay>
  let sortLoop = setInterval(function() {
      // If left > right, swap
      comparison_count = comparison_count + 1;
      
      cmp1 = sortIndex
      cmp2 = sortIndex + gap;
      
      if (cmp2 < ITEMS &&
	  list[cmp1] > list[cmp2]) {
	  swap_count += 1;
      // Keep setting finished just to be safe.
      finished = false;
      
      // ol-switcharoo
      tmp = list[cmp2];
      list[cmp2] = list[cmp1];
      list[cmp1] = tmp;
	  cmp1 *= -1; // flags that a swap is being done
	  cmp2 *= -1; // flags that a swap is being done
      
    }
      // Flag that the background and bars need updating.
      updateBG = true;
      updateBars = true;
      
    sortIndex++;
    
    // Reached end of list.
    // If list has been scanned once with no swaps, 
    // sortFinish will be set and sort will end.
    // Otherwise start over from 1.
    if (sortIndex + gap >= ITEMS) {
	if (finished) {
            sortFinished = true;
            clearInterval(sortLoop);
	} 
	sortIndex = 0;
	gap = Math.floor(gap / shrink)
	if (gap <= 1) {
	    gap = 1;
	    finished = true;
	}
    }
      // Repeat once every <sortDelay>.
  }, sortDelay);
}

// Setup initializes the canvas as well as the list of random nums.
function setup() {
  setupCanvas();
  initList();
}

// loopBlock is briefly enabled when sorting has finished to give a view of the finished sort.
let loopBlock = false;
function loop() {
  if (!loopBlock) {
    // If background needs updated, redraw background.
    if (updateBG) {
      updateBG = false; 
      drawBackground();
    }
    // If bars need updated, replot.
    if (updateBars) {
      updateBars = false;
      plotBars();
    }
    
    // Starts the sort if it isn't looping already.
    if (!sortStarted)
      console.log("Sort started");
      //sortStart();
    // Checks if sort has completed. Briefly blocks looping while re-initializing the list, sortStarted, and sortFinished variables.
    if (sortFinished) {
      loopBlock = true;
      setTimeout(function() {
        initList();
        sortStarted = false;
        sortFinished = false;
        loopBlock = false;
      }, restartDelay);
    }
  }
}

// Main function which runs the setup and holds the main infinite loop.
(function main() {
  // Setup the canvas and list.
  setup();
  (function mainLoop() {
    loop();
    // requestAnimationFrame calls mainLoop infinitely
    requestAnimationFrame(mainLoop);
  })();
})();