/*
 * File    : ExtendedPlayer.java
 * Created : 25-oct-2001 10:10
 * By      : fbusquets
 *
 * JClic - Authoring and playing system for educational activities
 *
 * Copyright (C) 2000 - 2018 Francesc Busquets & Departament
 * d'Educacio de la Generalitat de Catalunya
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details (see the LICENSE file).
 */

package edu.xtec.jclic;

import edu.xtec.jclic.accessibility.FressaFunctions;
import edu.xtec.jclic.fileSystem.*;
import edu.xtec.jclic.misc.Utils;
import edu.xtec.jclic.project.*;
import edu.xtec.util.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;

/**
 * @author Francesc Busquets (fbusquets@xtec.cat)
 * @version 13.08.29
 */
public class ExtendedPlayer extends Player {

  JFrame debugFrame = null;
  public static final String MESSAGES_BUNDLE = "messages.PlayerMessages";
  protected int recentFilesOffset;
  protected JMenuBar menuBar;
  protected JMenu fileMenu, recentFilesMenu, activityMenu, toolsMenu, helpMenu;
  protected PlayerSettings settings;
  protected FressaFunctions fressa;

  /** Creates new ExtendedPlayer */
  public ExtendedPlayer(Options options) {
    super(options);
  }

  @Override
  protected void init() {
    settings = PlayerSettings.loadPlayerSettings(this);
    super.init();
    settings.checkLibrary();
    if (settings.fressaEnabled)
      fressa = new FressaFunctions(options);
  }

  protected void doInstall(String fileName) {
    if (settings.promptPassword(this, new String[] { "install_info_description", "settings_passwordRequired" })) {
      try {
        ProjectInstallerDlg pi = ProjectInstallerDlg.getProjectInstallerDlg(this, settings.libraryManager, fileName);
        if (pi != null) {
          pi.setVisible(true);
          if (pi.result != null && !pi.cancel) {
            if (pi.launchNow && pi.pathToMainProject != null)
              load(pi.pathToMainProject, null);
            else
              launchProjectLibrary(pi.result);
          }
        }
      } catch (Exception ex) {
        System.err.println("Error installing: " + ex.getMessage());
      }
    }
  }

  @Override
  public boolean start(String fullPath, String sequence) {
    boolean result = super.start(fullPath, sequence);
    if (!result) {
      try {
        ProjectLibrary pl = settings.libraryManager.getAutoStartProjectLibrary();
        if (pl != null)
          launchProjectLibrary(pl);
      } catch (Exception ex) {
        System.err.println("Error loading autoStart project library!\n" + ex);
      }
    }
    return result;
  }

  @Override
  public boolean load(String fullPath, String sequence) {
    boolean result = false;
    if (fullPath != null && sequence == null && fullPath.endsWith(ProjectInstaller.INSTALLER_EXTENSION))
      doInstall(fullPath);
    else
      result = super.load(fullPath, sequence);
    return result;
  }

  @Override
  public Messages setMessages() {
    super.setMessages();
    messages.addBundle(MESSAGES_BUNDLE);
    return messages;
  }

  @Override
  protected FileSystem createFileSystem() {
    return settings.fileSystem;
  }

  protected void createMenu() {

    menuBar = new JMenuBar();

    fileMenu = new JMenu(messages.get("m_File"));
    fileMenu.setMnemonic(messages.get("m_File_Mnemonic").charAt(0));
    fileMenu.add(new KJMenuItem(getAction(ACTION_OPEN_FILE)));
    fileMenu.add(new KJMenuItem(getAction(ACTION_OPEN_URL)));
    menuBar.add(fileMenu);

    activityMenu = new JMenu(messages.get("m_Activity"));
    activityMenu.setMnemonic(messages.get("m_Activity_Mnemonic").charAt(0));
    activityMenu.add(new KJMenuItem(getAction(ACTION_NEXT)));
    activityMenu.add(new KJMenuItem(getAction(ACTION_PREV)));
    activityMenu.add(new KJMenuItem(getAction(ACTION_RETURN)));
    activityMenu.add(new KJMenuItem(getAction(ACTION_RESET)));
    activityMenu.addSeparator();
    activityMenu.add(new KJMenuItem(getAction(ACTION_INFO)));
    activityMenu.add(new KJMenuItem(getAction(ACTION_HLP)));
    activityMenu.add(new KJMenuItem(getAction(ACTION_REPORTS)));
    activityMenu.addSeparator();
    activityMenu.add(new KJMenuItem(getAction(ACTION_AUDIO)));
    menuBar.add(activityMenu);

    toolsMenu = new JMenu(messages.get("m_Tools"));
    toolsMenu.setMnemonic(messages.get("m_Tools_Mnemonic").charAt(0));
    toolsMenu.add(new KJMenuItem(getAction(ACTION_LIBRARIES)));
    toolsMenu.add(new KJMenuItem(getAction(ACTION_SETTINGS)));
    menuBar.add(toolsMenu);

    helpMenu = new JMenu(messages.get("m_Help"));
    helpMenu.setMnemonic(messages.get("m_Help_Mnemonic").charAt(0));
    helpMenu.add(new KJMenuItem(getAction(ACTION_ABOUT)));
    menuBar.add(helpMenu);
  }

  protected void postCreateMenu() {
    fileMenu.addSeparator();
    fileMenu.add(new KJMenuItem(getAction(ACTION_EXIT)));
    fileMenu.addSeparator();
    recentFilesMenu = fileMenu;
    recentFilesOffset = fileMenu.getItemCount();
    updateRecentFilesMenu();
  }

  @Override
  public void addTo(RootPaneContainer cont, Object constraints) {
    super.addTo(cont, constraints);
    checkMenu(false);
  }

  protected void checkMenu(boolean recreate) {
    JRootPane rp = getRootPane();
    if (rp == null)
      return;

    if (recreate || rp.getJMenuBar() == null) {
      if (recreate || menuBar == null) {
        createMenu();
        postCreateMenu();
      }
      rp.setJMenuBar(menuBar);
      rp.revalidate();
    }
  }

  protected void updateRecentFilesMenu() {
    if (recentFilesMenu != null && recentFilesOffset >= 0) {
      JMenuItem jmi;
      int itemsToRemove = recentFilesMenu.getItemCount() - recentFilesOffset;
      for (int i = 0; i < itemsToRemove; i++)
        recentFilesMenu.remove(recentFilesOffset);
      for (int i = 0; i < PlayerSettings.MAX_RECENT; i++) {
        if (settings.recentFiles[i] != null) {
          String s = settings.recentFiles[i];
          int k = s.lastIndexOf('\\');
          if (k < 0)
            k = s.lastIndexOf('/');
          if (k >= 0)
            s = s.substring(k + 1);
          createMenuItem(recentFilesMenu, Integer.toString(i + 1) + ". " + s, "recent" + i, true,
              KeyStroke.getKeyStroke(KeyEvent.VK_1 + i, ActionEvent.ALT_MASK));
        }
      }
    }
  }

  JMenuItem createMenuItem(JComponent parent, String text, String actionCommand, boolean mnemonic,
      KeyStroke accelerator) {
    JMenuItem jmi = new JMenuItem(text);
    if (actionCommand != null) {
      jmi.setActionCommand(actionCommand);
      jmi.addActionListener(this);
    }
    if (mnemonic)
      jmi.setMnemonic(jmi.getText().charAt(0));
    if (accelerator != null)
      jmi.setAccelerator(accelerator);
    parent.add(jmi);
    return jmi;
  }

  public static final int ACTION_OPEN_FILE = NUM_ACTIONS, ACTION_OPEN_URL = NUM_ACTIONS + 1,
      ACTION_EXIT = NUM_ACTIONS + 2, ACTION_SETTINGS = NUM_ACTIONS + 3, ACTION_LIBRARIES = NUM_ACTIONS + 4,
      ACTION_ABOUT = NUM_ACTIONS + 5, NUM_ACTIONS_EXT = NUM_ACTIONS + 6;

  public static final String[] ACTION_NAME_EXT = { "openFile", "openUrl", "exit", "settings", "libraries",
      "helpAbout" };
  public static final String[] ACTION_ICONS_EXT = { "icons/file_open.gif", "icons/world.gif", "icons/exit_small.gif",
      "icons/settings.gif", "icons/database.gif", "icons/help.gif" };

  @Override
  protected int getNumActions() {
    return NUM_ACTIONS_EXT;
  }

  @Override
  protected void buildActions() {
    super.buildActions();
    actions[ACTION_OPEN_FILE] = new AbstractAction() {
      public void actionPerformed(ActionEvent ev) {
        FileSystem fs = project.getFileSystem();
        if (fs.isUrlBased())
          fs = settings.fileSystem;
        int[] filters = { Utils.ALL_CLIC_FF, Utils.INSTALL_FF, Utils.ALL_JCLIC_FF };
        String result = fs.chooseFile(null, false, filters, options, null, ExtendedPlayer.this, false);
        if (result != null) {
          String fileName = fs.getFullFileNamePath(result);
          if (load(fileName, null))
            addRecentFile(fileName);
        }
      }
    };

    actions[ACTION_OPEN_URL] = new AbstractAction() {
      public void actionPerformed(ActionEvent ev) {
        String url = messages.showInputDlg(ExtendedPlayer.this, "URL_OPEN", "URL", "http://", "URL_OPEN", false);
        if (url != null) {
          url = url.trim();
          if (url.indexOf("://", 7) >= 0)
            url = url.substring(7);
          if (url.length() > 0 && !url.equals("http://")) {
            if (load(url, null))
              addRecentFile(url);
          }
        }
      }
    };

    actions[ACTION_EXIT] = new AbstractAction() {
      public void actionPerformed(ActionEvent ev) {
        exit();
      }
    };

    actions[ACTION_SETTINGS] = new AbstractAction() {
      public void actionPerformed(ActionEvent ev) {
        String currentLook = options.getString(LFUtil.LOOK_AND_FEEL);
        String currentLanguage = options.getString(Messages.LANGUAGE);
        String currentCountry = options.getString(Messages.COUNTRY);
        String currentVariant = options.getString(Messages.VARIANT);
        String currentSkin = options.getString(SKIN);
        String currentReporterClass = settings.reporterClass;
        String currentReporterParams = settings.reporterParams;
        boolean currentReporterEnabled = settings.reporterEnabled;
        String currentMediaSystem = settings.mediaSystem;
        if (settings.edit(ExtendedPlayer.this)) {
          settings.save();
          options.syncProperties(settings.getProperties(), false);
          if (!settings.skin.equals(currentSkin)) {
            initSkin();
            setSkin(null);
          } else if (getSkin() != null) {
            AbstractButton bt = getSkin().getButton(ACTION_AUDIO);
            if (bt != null)
              bt.setSelected(!audioEnabled);
          }
          boolean recreateMenu = false;
          if (!settings.lookAndFeel.equals(currentLook)) {
            options.setLookAndFeel();
            recreateMenu = true;
          }
          if (settings.language != null && (!StrUtils.compareObjects(settings.language, currentLanguage)
              || !StrUtils.compareObjects(settings.country, currentCountry)
              || !StrUtils.compareObjects(settings.variant, currentVariant))) {
            setMessages();
            recreateMenu = true;
          }
          if (recreateMenu) {
            checkMenu(true);
          }
          if (settings.reporterEnabled && (!settings.reporterClass.equals(currentReporterClass)
              || !settings.reporterParams.equals(currentReporterParams))) {
            initReporter();
          }
          audioEnabled = settings.soundEnabled;
          edu.xtec.jclic.media.EventSounds.globalEnabled = settings.systemSounds;
          if (!currentMediaSystem.equals(settings.mediaSystem)) {
            options.put(MEDIA_SYSTEM, settings.mediaSystem);
            edu.xtec.jclic.media.CheckMediaSystem.check(options, false);
            createEventSounds();
          }
        }
      }
    };

    actions[ACTION_LIBRARIES] = new AbstractAction() {
      public void actionPerformed(ActionEvent ev) {
        try {
          ProjectLibrary pl = settings.libraryManager.selectProjectLibrary(true, false);
          if (pl != null)
            launchProjectLibrary(pl);
        } catch (Exception ex) {
          messages.showErrorWarning(ExtendedPlayer.this, "error_launchLibrary", ex);
        }
      }
    };

    actions[ACTION_ABOUT] = new AbstractAction() {
      public void actionPerformed(ActionEvent ev) {
        showAbout(false);
      }
    };
  }

  @Override
  protected String getActionName(int actionId) {
    if (actionId >= NUM_ACTIONS && actionId < NUM_ACTIONS_EXT)
      return ACTION_NAME_EXT[actionId - NUM_ACTIONS];
    return super.getActionName(actionId);
  }

  @Override
  protected Icon getActionIcon(int actionId) {
    if (actionId >= NUM_ACTIONS && actionId < NUM_ACTIONS_EXT)
      return ResourceManager.getImageIcon(ACTION_ICONS_EXT[actionId - NUM_ACTIONS]);
    return super.getActionIcon(actionId);
  }

  @Override
  protected boolean processActionEvent(String ac) {
    if (ac.startsWith("recent") && ac.length() > 6) {
      try {
        int i = Integer.parseInt(ac.substring(6));
        if (i >= 0 && i < PlayerSettings.MAX_RECENT && settings.recentFiles[i] != null)
          load(settings.recentFiles[i], null);
      } catch (Exception ex) {
        System.err.println("invalid command: " + ac);
      }
    } else
      return super.processActionEvent(ac);

    return true;
  }

  protected void launchProjectLibrary(ProjectLibrary pl) {
    if (pl != null) {
      setProject(null);
      edu.xtec.jclic.media.MediaContent mc = new edu.xtec.jclic.media.MediaContent();
      mc.externalParam = pl.getFullPath();
      mc.mediaFileName = pl.activitySequence.getElement(0, false).getTag();
      mc.mediaType = edu.xtec.jclic.media.MediaContent.RUN_CLIC_PACKAGE;
      playMedia(mc, null);
    }
  }

  protected void addRecentFile(String fName) {
    settings.addRecentFile(fName);
    updateRecentFilesMenu();
    settings.save();
  }

  /**
   * FressaFunctions offers special accessibility features like atomatic scanning
   * and voice synthesis.
   *
   * @return The FressaFunctions object, or <CODE>null</CODE> if accessibility
   *         features are not enabled
   */
  @Override
  public edu.xtec.jclic.accessibility.FressaFunctions getFressa() {
    return fressa;
  }
}
