Presentation* presentation = nullptr;

void Presentation::synchronize() {
  for(auto& emulator : emulatorList) emulator->menu.setVisible(false);
  for(auto& emulator : emulatorList) {
    if(emulator->interface == program->active) {
      active = emulator;
      emulator->menu.setVisible(true);
    }
  }

  shaderNone.setChecked();
  if(config->video.shader == "None") shaderNone.setChecked();
  if(config->video.shader == "Blur") shaderBlur.setChecked();
  if(config->video.shader == "Display Emulation") shaderEmulation.setChecked();
  for(auto& shader : shaderList) {
    string name = notdir(config->video.shader.split<1>(".shader/")(0));
    if(name == shader->text()) shader->setChecked();
  }

  switch(config->video.scaleMode) {
  case 0: centerVideo.setChecked(); break;
  case 1: scaleVideo.setChecked(); break;
  case 2: stretchVideo.setChecked(); break;
  }
  aspectCorrection.setChecked(config->video.aspectCorrection);
  maskOverscan.setChecked(config->video.maskOverscan.enable);
  synchronizeVideo.setChecked(config->video.synchronize);
  synchronizeAudio.setChecked(config->audio.synchronize);
  muteAudio.setChecked(config->audio.mute);

  if(program->active == nullptr) {
    toolsMenu.setVisible(false);
  } else {
    toolsMenu.setVisible(true);
    saveStateMenu.setVisible(system().information.capability.states);
    loadStateMenu.setVisible(system().information.capability.states);
    stateMenuSeparator.setVisible(system().information.capability.states);
    resizeWindow.setVisible(config->video.scaleMode != 2);
    stateManager.setVisible(system().information.capability.states);
    cheatEditor.setVisible(system().information.capability.cheats);
    synchronizeTime.setVisible(system().rtc());
  }
}

void Presentation::setSystemName(string name) {
  if(active) active->menu.setText(systemName = name);
}

Presentation::Presentation() {
  bootstrap();
  loadShaders();
  setGeometry({256, 256, 720, 480});
  windowManager->append(this, "Presentation");

  setTitle({::Emulator::Name, " v", ::Emulator::Version});
  setBackgroundColor({0, 0, 0});
  setMenuVisible();
  setStatusVisible();

  setDroppable();
  viewport.setDroppable();

  loadMenu.setText("Library");
  settingsMenu.setText("Settings");
    videoMenu.setText("Video");
      centerVideo.setText("Center");
      scaleVideo.setText("Scale");
      stretchVideo.setText("Stretch");
      RadioItem::group(centerVideo, scaleVideo, stretchVideo);
      aspectCorrection.setText("Aspect Correction");
      maskOverscan.setText("Mask Overscan");
    shaderMenu.setText("Shader");
      shaderNone.setText("None");
      shaderBlur.setText("Blur");
      shaderEmulation.setText("Display Emulation");
    synchronizeVideo.setText("Synchronize Video");
    synchronizeAudio.setText("Synchronize Audio");
    muteAudio.setText("Mute Audio");
    configurationSettings.setText("Configuration ...");
  toolsMenu.setText("Tools");
    saveStateMenu.setText("Save State");
      for(unsigned n = 0; n < 5; n++) saveStateItem[n].setText({"Slot ", 1 + n});
    loadStateMenu.setText("Load State");
      for(unsigned n = 0; n < 5; n++) loadStateItem[n].setText({"Slot ", 1 + n});
    resizeWindow.setText("Resize Window");
    stateManager.setText("State Manager");
    cheatEditor.setText("Cheat Editor");
    synchronizeTime.setText("Synchronize Time");

  append(loadMenu);
    for(auto& item : loadBootableMedia) loadMenu.append(*item);
  for(auto& systemItem : emulatorList) append(systemItem->menu);
  append(settingsMenu);
    settingsMenu.append(videoMenu);
      videoMenu.append(centerVideo);
      videoMenu.append(scaleVideo);
      videoMenu.append(stretchVideo);
      videoMenu.append(*new Separator);
      videoMenu.append(aspectCorrection);
      videoMenu.append(maskOverscan);
    settingsMenu.append(shaderMenu);
      shaderMenu.append(shaderNone);
      shaderMenu.append(shaderBlur);
      if(config->video.driver == "OpenGL") shaderMenu.append(shaderEmulation);
      if(shaderList.size() > 0) {
        shaderMenu.append(*new Separator);
        for(auto& shader : shaderList) shaderMenu.append(*shader);
      }
    settingsMenu.append(*new Separator);
    settingsMenu.append(synchronizeVideo);
    settingsMenu.append(synchronizeAudio);
    settingsMenu.append(muteAudio);
    if(Intrinsics::platform() != Intrinsics::Platform::MacOSX) {
      settingsMenu.append(*new Separator);
      settingsMenu.append(configurationSettings);
    }
  append(toolsMenu);
    toolsMenu.append(saveStateMenu);
      for(unsigned n = 0; n < 5; n++) saveStateMenu.append(saveStateItem[n]);
    toolsMenu.append(loadStateMenu);
      for(unsigned n = 0; n < 5; n++) loadStateMenu.append(loadStateItem[n]);
    toolsMenu.append(stateMenuSeparator);
    toolsMenu.append(resizeWindow);
    toolsMenu.append(stateManager);
    toolsMenu.append(cheatEditor);
    toolsMenu.append(synchronizeTime);

  append(layout);
  layout.append(viewport, {0, 0, 1, 1});

  onDrop = viewport.onDrop = [&](lstring paths) {
    if(paths.size() && directory::exists(paths[0])) {
      utility->loadMedia(paths[0]);
      setFocused();
    }
  };

  onSize = [&] {
    utility->resize();
  };

  onClose = [&] {
    setVisible(false);
    if(Intrinsics::platform() == Intrinsics::Platform::MacOSX) {
      utility->unload();
    } else {
      Application::quit();
    }
  };

  shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); };
  shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); };
  shaderEmulation.onActivate = [&] { config->video.shader = "Display Emulation"; utility->updateShader(); };
  centerVideo.onActivate  = [&] { config->video.scaleMode = 0; utility->resize(); };
  scaleVideo.onActivate   = [&] { config->video.scaleMode = 1; utility->resize(); };
  stretchVideo.onActivate = [&] { config->video.scaleMode = 2; utility->resize(); };
  aspectCorrection.onToggle = [&] { config->video.aspectCorrection = aspectCorrection.checked(); utility->resize(); };
  maskOverscan.onToggle = [&] { config->video.maskOverscan.enable = maskOverscan.checked(); };
  synchronizeVideo.onToggle = [&] { config->video.synchronize = synchronizeVideo.checked(); utility->synchronizeRuby(); };
  synchronizeAudio.onToggle = [&] { config->audio.synchronize = synchronizeAudio.checked(); utility->synchronizeRuby(); };
  muteAudio.onToggle = [&] { config->audio.mute = muteAudio.checked(); utility->synchronizeRuby(); };
  configurationSettings.onActivate = [&] { settings->setVisible(); };
  for(unsigned n = 0; n < 5; n++) saveStateItem[n].onActivate = [=] { utility->saveState(1 + n); };
  for(unsigned n = 0; n < 5; n++) loadStateItem[n].onActivate = [=] { utility->loadState(1 + n); };
  resizeWindow.onActivate = [&] { utility->resize(true); };
  stateManager.onActivate = [&] { tools->panels.setSelection(1); tools->setVisible(); };
  cheatEditor.onActivate = [&] { tools->panels.setSelection(0); tools->setVisible(); };
  synchronizeTime.onActivate = [&] { system().rtcsync(); };

  synchronize();
}

void Presentation::bootstrap() {
  for(auto& emulator : program->emulator) {
    for(auto& media : emulator->media) {
      if(media.bootable == false) continue;
      Item* item = new Item;
      item->setText({media.name, " ..."});
      item->onActivate = [=] { libraryManager->show(media.type); };
      loadBootableMedia.append(item);
    }
  }

  for(auto& emulator : program->emulator) {
    auto iEmulator = new Emulator;
    iEmulator->interface = emulator;

    iEmulator->menu.setText(emulator->information.name);
    iEmulator->power.setText("Power");
    iEmulator->reset.setText("Reset");
    iEmulator->unload.setText("Unload");

    for(auto& port : emulator->port) {
      auto iPort = new Emulator::Port;
      iPort->menu.setText(port.name);
      iEmulator->port.append(iPort);

      for(auto& device : port.device) {
        auto iDevice = new RadioItem;
        iDevice->setText(device.name);
        iDevice->onActivate = [=] { utility->connect(port.id, device.id); };
        iPort->group.append(*iDevice);
        iPort->device.append(iDevice);
      }

      RadioItem::group(iPort->group);
    }

    iEmulator->menu.append(iEmulator->power);
    if(emulator->information.resettable)
    iEmulator->menu.append(iEmulator->reset);
    iEmulator->menu.append(*new Separator);
    unsigned visiblePorts = 0;
    for(auto& iPort : iEmulator->port) {
      iEmulator->menu.append(iPort->menu);
      if(iPort->device.size() <= 1) iPort->menu.setVisible(false);
      else visiblePorts++;
      for(auto& iDevice : iPort->device) {
        iPort->menu.append(*iDevice);
      }
    }
    iEmulator->menu.append(iEmulator->controllerSeparator);
    if(visiblePorts == 0) iEmulator->controllerSeparator.setVisible(false);
    iEmulator->menu.append(iEmulator->unload);

    iEmulator->power.onActivate = {&Utility::power, utility};
    iEmulator->reset.onActivate = {&Utility::reset, utility};
    iEmulator->unload.onActivate = {&Utility::unload, utility};

    emulatorList.append(iEmulator);
  }
}

void Presentation::loadShaders() {
  //only the OpenGL driver has video shader support
  if(config->video.driver == "OpenGL") {
    string pathname = program->path("Video Shaders/");
    lstring shaders = directory::folders(pathname, "*.shader");
    for(auto& name : shaders) {
      auto shader = new RadioItem;
      shader->setText(name.split<1>(".shader/")(0));
      shader->onActivate = [=] {
        config->video.shader = {pathname, name};
        utility->updateShader();
      };
      shaderList.append(shader);
    }
  }

  nall::group<RadioItem> group;
  group.append(shaderNone);
  group.append(shaderBlur);
  group.append(shaderEmulation);
  for(auto& shader : shaderList) group.append(*shader);
  RadioItem::group(group);
}
