var Main = function () {
  var conf = TDEMO.SYNC.getConfig();
  var syncDevice = TDEMO.SYNC.getSyncDevice();

  var audio = false;

  //Initializing renderer
  var renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setClearColor(0x000000);
  renderer.autoClear = false;

  //RENDERING PIPELINE
  var composer = new THREE.EffectComposer(renderer);

  var fades = new THREE.ShaderPass(THREE.ParaguayFades);
  fades.uniforms["brightness"].value = 0.0;
  fades.uniforms["fade"].value = 1.0;
  fades.uniforms["fadeColor"].value = new THREE.Vector3(0.0, 0.0, 0.0);

  var glitchPass = new THREE.GlitchPass();

  var colorcorrect = new THREE.ShaderPass(THREE.ParaguayColorCorrect);
  //calibrate this according to screen!
  colorcorrect.uniforms["gamma"].value = new THREE.Vector3(2.0, 2.0, 2.0);
  colorcorrect.uniforms["fade"].value = 1.0;
  colorcorrect.uniforms["fadeColor"].value = new THREE.Vector3(0.0, 0.0, 0.0);

  colorcorrect.renderToScreen = true;

  composer.addPass(fades);
  composer.addPass(glitchPass);
  composer.addPass(colorcorrect);

  var parts = [];
  var partIndex = false;
  var mainPart = false;

  var logoVisible = false;

  var started = false;
  var timeElapsed = 0;
  var clock = new THREE.Clock();

  //The main loop!
  var mainloop = function () {
    if (!started) {
      started = true;
      audio = document.getElementById("audio");
      mainPart.prepare(0);

      if (conf.isDemoMode()) {
        audio.play();
      } else {
        audio.pause();
        audio.currentTime = conf.getRow() / conf.getRowRate();
      }
    }

    timeElapsed = audio.currentTime;
    if (!audio.paused) {
      //otherwise we may jump into a point in the audio where there's
      //no timeframe, resulting in Rocket setting row 2 and we report
      //row 1 back - thus Rocket spasming out
      conf.setRow(timeElapsed * conf.getRowRate());
      // this informs Rocket where we are
      syncDevice.update(conf.getRow());
    }

    if (mainPart.edge !== false) {
      var additive = TDEMO.SYNC.getAdditive();
      mainPart.edge.uniforms["additive"].value = additive;
    }

    var bright = TDEMO.SYNC.getBrightness();
    fades.uniforms["brightness"].value = bright;

    var fade = TDEMO.SYNC.getFadeValue();
    fades.uniforms["fade"].value = fade;

    var fadeAll = TDEMO.SYNC.getFadeAll();
    colorcorrect.uniforms["fade"].value = fadeAll;

    var fadeColor = TDEMO.SYNC.getFadeColor();
    fades.uniforms["fadeColor"].value = fadeColor;
    colorcorrect.uniforms["fadeColor"].value = fadeColor;

    var negate = TDEMO.SYNC.getNegate();
    fades.uniforms["negate"].value = negate;

    var glitch = TDEMO.SYNC.getGlitch();
    if (glitch > 0) {
      glitchPass.goWild = true;
    } else {
      glitchPass.goWild = false;
    }
    glitchPass.time = timeElapsed;
    glitchPass.snow = TDEMO.SYNC.getSnow();

    var grayscale = TDEMO.SYNC.getGrayscale();
    fades.uniforms["grayscale"].value = grayscale;

    var showLogo = TDEMO.SYNC.getShowText();
    var logo = document.getElementById("credits");
    if (showLogo > 0) {
      logo.style.display = "block";
      logoVisible = true;
      logo.style.opacity = showLogo;
    } else if (showLogo <= 0 && logoVisible === true) {
      logo.style.display = "none";
      logoVisible = false;
    }

    var index = TDEMO.SYNC.getPart();
    if (index !== partIndex && index < parts.length && index >= 0) {
      partIndex = index;
      mainPart.finish();
      mainPart = parts[partIndex];
      mainPart.prepare(timeElapsed);
    }

    var delta = clock.getDelta();
    mainPart.animate(timeElapsed, delta);

    //renderer.clear();
    composer.render(delta);

    if (conf.isDemoMode() || !audio.paused) {
      if (audio.ended && conf.isDemoMode()) {
        cancelAnimationFrame(mainloop);
      } else {
        requestAnimationFrame(mainloop);
      }
    } else {
      cancelAnimationFrame(mainloop);
    }
  };

  //Public interface
  var state = {
    setRendererSize: function (width, height) {
      renderer.setSize(width, height);
      composer.setSize(width, height);

      renderer.domElement.style.width = width;
      renderer.domElement.style.height = height;

      document.getElementById("demo").appendChild(renderer.domElement);
    },

    getRendererSize: function () {
      return [renderer.domElement.width, renderer.domElement.height];
    },

    setParts: function (p) {
      parts = p;
      mainPart = parts[0];
      partIndex = 0;
    },

    getRenderer: function () {
      return renderer;
    },

    getComposer: function () {
      return composer;
    },

    disableCopyPass: function () {
      copyPass.enabled = false;
    },

    enableCopyPass: function () {
      copyPass.enabled = true;
    },

    mainloop: mainloop,
  };
  return state;
};

TDEMO.MAIN = Main();
