/**
 *  Copyright © 2021-2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Exhibit B - "Incompatible With Secondary Licenses" Notice
 *
 *  This Source Code Form is "Incompatible With Secondary Licenses",
 *  as defined by the Mozilla Public License, v. 2.0.
 *
 *  In short:
 *  - This file may be used, modified, and distributed under MPL 2.0 only.
 *  - It may NOT be relicensed under GPL, LGPL, AGPL, or any other Secondary License.
 *
 *  Rationale:
 *  - Ensures that the code remains MPL-2.0.
 *  - Avoids legal conflicts with GPL-licensed libraries (e.g., VideoLAN).
 *  - Maximizes usability for commercial and security-critical applications.
 *
 */
package net.javacomm.client.administer;

import java.awt.Color;
import java.awt.Dimension;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.MultilingualString;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.transfer.TransferBenutzerkonto;
import net.javacomm.transfer.TransferConfig;
import net.javacomm.transfer.TransferOdxModulPermission;
import net.javacomm.transfer.TransferRoomfilter;
import net.javacomm.transfer.TransferUser;
import net.javacomm.window.manager.Control;
import net.javacomm.window.manager.Frames;
import net.javacomm.window.manager.WM;
import net.javacomm.window.manager.WindowManagerInternalFrame;



@SuppressWarnings("serial")
public class AdministratorFrame extends WindowManagerInternalFrame {

  class FrameAction extends InternalFrameAdapter {

    @Override
    public void internalFrameClosing(InternalFrameEvent event) {
      domain.removeAllListener();
      mailserver.removeAllListener();
      forum.removeAllListener();
      antraegeVerwalten.removeAllListener();
      chatfilter.removeAllListener();
      versionen.removeAllListener();
//      modul.removeAllListener();
      anwender.removeAllListener();
      chatmodul.removeAllListener();
      changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.CLOSE);
    }

  }

  private final static Logger log = LogManager.getLogger(AdministratorFrame.class);
  public final static int WIDTH = 860;

  public final static int HEIGHT = 500;
  private JTabbedPane tabbedPane = new JTabbedPane();
  private JDomain domain = new JDomain();
  private JMailserver mailserver = new JMailserver();
  private JChatfilter chatfilter = new JChatfilter();
  private JBenutzerVerwalten antraegeVerwalten = new JBenutzerVerwalten();
  private JAdministerForum forum = new JAdministerForum();
  private JChatModul chatmodul = new JChatModul();
  private JProgrammversionen versionen = new JProgrammversionen();
  private JSpitzname spitzname = new JSpitzname();
  private JAnwender anwender = new JAnwender();
  private TransferOdxModulPermission odxPermission;
  private TransferBenutzerkonto benutzerkonto;
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private TransferConfig config;
  private ChangeListener changeListener;
  private ArrayList<String> list;
  private MultilingualString multilingualDomain = new MultilingualString(KEY.LABEL_DOMAENE);
  private MultilingualString multilingualMailserver = new MultilingualString(KEY.STRING_MAILSERVER);
  private MultilingualString multilingualForum = new MultilingualString(KEY.FORUM);
  private MultilingualString multilingualChatmodul = new MultilingualString(KEY.STRING_CHAT_MODULE);
  private MultilingualString multilingualBenutzerantraege = new MultilingualString(
      KEY.STRING_BENUTZERANTRAEGE
  );
  private MultilingualString multilingualChatfilter = new MultilingualString(KEY.STRING_RAUMFILTER);
  private MultilingualString multilingualProgrammversionen = new MultilingualString(
      KEY.STRING_PROGRAMMVERSIONEN
  );
  private MultilingualString multilingualSpitznamen = new MultilingualString(KEY.STRING_SPITZNAME);
  private MultilingualString multilingualAnwender = new MultilingualString(KEY.STRING_ANWENDER);

  private FrameAction frameAction = new FrameAction();

  public AdministratorFrame() {
    setFrameIcon(new ImageIcon(getClass().getResource(Resource.ADMINISTRATOR_16X16)));
    setMaximizable(true);
    setResizable(true);
    setIconifiable(true);
    setClosable(true);
    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    setContentPane(tabbedPane);
    addInternalFrameListener(frameAction);
    setMinimumSize(new Dimension(WIDTH, HEIGHT));
    setSize(WIDTH, HEIGHT);
    init();
  }



  @Override
  public void activated() {
    try {
      setSelected(true);
      windowManager.setActivNode(title);
    }
    catch (PropertyVetoException e) {}
  }



  public void addAdministratorFrameListener(PropertyChangeListener listener) {
    changes.addPropertyChangeListener(listener);
  }



  /**
   * Die Spaltenüberschriften werden zentriert.
   */
  public void centerHeader() {
    antraegeVerwalten.centerHeader();
  }



  /**
   * Deregisters the filters selected by the user.
   *
   * @return the list of deregistered filters
   */
  public List<String> deregisterFilter() {
    return chatfilter.deregisterFilter();
  }



  public void flipLogicallyDelete() {
    anwender.flipLogicallyDelete();
  }



  public String getAdminPostfach() {
    return mailserver.getAdministratorPostfach();
  }



  public List<TransferUser> getBenutzerantraege() {
    return antraegeVerwalten.getAntraege();
  }



  /**
   * Das Benutzerkonto wurde gelöscht oder zurückgeholt.
   *
   * @return logisches Löschen
   */
  public TransferBenutzerkonto getBenutzerkonto() {
    return benutzerkonto;
  }



  @Override
  public String getFrameTitleId() {
    return title;
  }



  public TransferConfig getKonfigurationsdaten() {
    return config;
  }



  /**
   * Alle verbotenen Spitznamen werden zurückgegeben.
   *
   * @return verboten Spitznamen
   */
  public List<String> getNicknames() {
    return Collections.list(spitzname.getNicknames());
  }



  /**
   * Für einen Anwender wird die ODX-Berechtigung mitgeteilt.
   *
   * @return die ODX-Berechtigung
   */
  public TransferOdxModulPermission getOdxuser() {
    return odxPermission;
  }



  public List<String> getProgrammversionen() {
    return Collections.list(versionen.getVersionen());
  }



  public List<TransferRoomfilter> getRaumfilterliste() {
    Enumeration<String> enums = chatfilter.getFilterliste();
    ArrayList<TransferRoomfilter> transferfilter = new ArrayList<>();
    while (enums.hasMoreElements()) {
      TransferRoomfilter tmp = new TransferRoomfilter();
      tmp.setRoomfilter(enums.nextElement());
      transferfilter.add(tmp);
    }
    return transferfilter;
  }



  public String getSmptUser() {
    return mailserver.getBenutzername();
  }



  public String getSmtpHost() {
    return mailserver.getHost();
  }



  public char[] getSmtpPassword() {
    return mailserver.getPasswort();
  }



  public int getSmtpPort() throws StringException {
    return mailserver.getPort();
  }



  @Override
  public Frames getType() {
    return Frames.ADMINISTRATOR;
  }



  public void init() {
    domain.addDomainListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          save();
          break;
        default:
          break;
      }
    });
    mailserver.addMailserverListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case TESTMAIL:
          testmail();
          break;
        default:
          break;
      }
    });
    forum.addForumListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          save();
          break;
        default:
          break;
      }
    });
    chatmodul.addChatmodulListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          // TODO Stunden spiechern
          save();
          break;
        default:
          break;
      }
    });
    antraegeVerwalten.addAntraegeListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          saveBenutzerantraege();
          break;
        default:
          break;
      }
    });
    list = new ArrayList<>();

    chatfilter.addRaumfilterListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case ADD:
          saveRaumfilter();
          break;
        case REMOVE:
          removeRaumfilter();
          break;
        case SAVE:
          break;
        default:
          break;
      }
    });
    versionen.addProgrammversionenListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          saveProgrammversionen();
          break;
        default:
          break;
      }
    });
    spitzname.addNicknamesListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          saveNicknames();
          break;
        default:
          break;
      }
    });
    anwender.addAnwenderListener(event -> {
      Control control = (Control) event.getNewValue();
      switch(control) {
        case UPDATE:
          JScrollAnwender.Update update = (JScrollAnwender.Update) event.getOldValue();
          benutzerkonto = new TransferBenutzerkonto();
          benutzerkonto.setLdelete(update.isDeleted());
          benutzerkonto.setUid(update.getUserid());
          saveBenutzerkonten();
          break;
        case CLOSE:
          try {
            setClosed(true);
          }
          catch (PropertyVetoException e) {}
          break;
        case SAVE:
          throw new UnsupportedOperationException("Logisch löschen speichern");
        default:
          break;
      }
    });

    tabbedPane.addTab(multilingualDomain.toString(), domain);
    tabbedPane.addTab(multilingualMailserver.toString(), mailserver);
    tabbedPane.addTab(multilingualForum.toString(), forum);
    tabbedPane.addTab(multilingualChatmodul.toString(), chatmodul);
    tabbedPane.addTab(multilingualBenutzerantraege.toString(), antraegeVerwalten);
    tabbedPane.addTab(multilingualChatfilter.toString(), chatfilter);
    tabbedPane.addTab(multilingualProgrammversionen.toString(), versionen);
    tabbedPane.addTab(multilingualSpitznamen.toString(), spitzname);
//    tabbedPane.addTab(multilingualModul.toString(), modul);
    tabbedPane.addTab(multilingualAnwender.toString(), anwender);

    changeListener = new ChangeListener() {

      @Override
      public void stateChanged(ChangeEvent event) {
        int index = tabbedPane.getSelectedIndex();
        if (index == -1) return;
        String filter = tabbedPane.getTitleAt(index);
        switch(filter) {
          case "Raumfilter":
            chatfilter.setFilterliste(Collections.list(chatfilter.getFilterliste()));
            break;
          default:
            return;
        }
      }
    };
    tabbedPane.addChangeListener(changeListener);

  }



  @Override
  public void insertWM(WM value) {
    windowManager.addWindow(value);
  }



  /**
   * Registers this room filter.
   * 
   * @return the registered filter
   */
  public String registerFilter() {
    return chatfilter.registerFilter();
  }



  public void removeAdministratorFrameListener(PropertyChangeListener listener) {
    changes.removePropertyChangeListener(listener);
  }



  public void removeAllListener() {
    for (PropertyChangeListener listeners : changes.getPropertyChangeListeners()) {
      changes.removePropertyChangeListener(listeners);
    }
    tabbedPane.removeChangeListener(changeListener);
    // die anderen auch noch entfernen
    removeInternalFrameListener(frameAction);
  }



  void removeRaumfilter() {
    changes
        .firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.DEREGISTER_RAUMFILTER);
  }



  @Override
  public void removeWM(WM frame) {
    windowManager.removeWM(frame);
  }



  /**
   * Domain oder Mailserver haben eine Speicheraktivität ausgelöst.
   *
   */
  void save() {
    config = transfer();
    try {
      config.setMailSmtpPort(mailserver.getPort());
      config.setFlipToForum(forum.getZeitschwelleForum());
      config.setHours(chatmodul.getHours());
      changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.SAVE);
    }
    catch (StringException e) {
      JOptionPane.showMessageDialog(
          AdministratorFrame.this,
          "<html>" + "Der <b><span style=\"color:red\">Port</span></b> muss ein Zahlenwert sein." + "</html>",
          "Speichern fehlgeschlagen", JOptionPane.ERROR_MESSAGE
      );
    }
    catch (ZeitschwelleException e) {
      JOptionPane.showMessageDialog(
          AdministratorFrame.this,
          "<html>"
              + "Der <b><span style=\"color:red\">Schwellenwert</span></b> muss im Zahlenbereich [1..1440] liegen."
              + "</html>",
          "Speichern fehlgeschlagen", JOptionPane.ERROR_MESSAGE
      );
    }
  }



  /**
   *
   * Alle Benutzeranträge mit einem neuen Status werden gespeichert.
   *
   */
  void saveBenutzerantraege() {
    changes
        .firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.SAVE_BENUTZERANTRAEGE);
  }



  /**
   * Ein Benutzerkonto wird logisch gelöscht oder zurückgeholt.
   */
  public void saveBenutzerkonten() {
    changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.UPDATE);
  }



  /**
   * Alle verbotenen Nicknames werden gespeichert.
   *
   */
  public void saveNicknames() {
    changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.SAVE_NICKNAMES);
  }



  /**
   * Die ODX-Berechtigung wird für einen Anwender gespeichert.
   */
  public void saveOdxmodul() {
    changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.UPDATE_ODX);
  }



  /**
   * Alle veralteten Programmversionen werden gespeichert.
   *
   */
  public void saveProgrammversionen() {
    changes
        .firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.SAVE_PROGRAMMVERSIONEN);
  }



  /**
   * Alle Raumfilter werden gespeichert.
   *
   */
  void saveRaumfilter() {
    changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.REGISTER_RAUMFILTER);
  }



  @Override
  public void setBackgroundGradient(Color top, Color bottom) {
    windowManager.setBackgroundGradient(top, bottom);
  }



  public void setBenutzerantraege(List<TransferUser> value) {
    antraegeVerwalten.setAntraege(value);
  }



  /**
   * Alle Benutzerkonten wurden ausgelesen und werden als nächstes angezeigt.
   *
   *
   * @param benutzerkonten
   *                       alle Konten
   */
  public void setBenutzerkonten(ArrayList<TransferBenutzerkonto> benutzerkonten) {
    anwender.setBenutzerkonto(benutzerkonten);
  }



  @Override
  public void setFrameTitleId(String id) {
    setTitle(id);
  }



  public void setKonfigurationsdaten(TransferConfig value) {
    mailserver.setHost(value.getMailSmtpHost());
    mailserver.setBenutzername(value.getMailSmtpUser());
    mailserver.setPort(value.getMailSmtpPort());
    mailserver.setAdministratorPostfach(value.getAdminPostfach());
    mailserver.setPasswort(value.getSmtpPasswort());
    domain.setDomain(value.getDomain());
    domain.setIsPublic(value.getIsPublic());
    forum.setZeitschwelleForum(value.getFlipToForum());
    chatmodul.setHours(value.getHours());
  }



  @Override
  public void setLanguage(ISO639 code) {
    multilingualDomain.setLanguage(code);
    tabbedPane.setTitleAt(0, multilingualDomain.toString());
    multilingualMailserver.setLanguage(code);
    tabbedPane.setTitleAt(1, multilingualMailserver.toString());
    multilingualForum.setLanguage(code);
    tabbedPane.setTitleAt(2, multilingualForum.toString());
    multilingualChatmodul.setLanguage(code);
    tabbedPane.setTitleAt(3, multilingualChatmodul.toString());
    multilingualBenutzerantraege.setLanguage(code);
    tabbedPane.setTitleAt(4, multilingualBenutzerantraege.toString());
    multilingualChatfilter.setLanguage(code);
    tabbedPane.setTitleAt(5, multilingualChatfilter.toString());
    multilingualProgrammversionen.setLanguage(code);
    tabbedPane.setTitleAt(6, multilingualProgrammversionen.toString());
    multilingualSpitznamen.setLanguage(code);
    tabbedPane.setTitleAt(7, multilingualSpitznamen.toString());

    multilingualAnwender.setLanguage(code);
    tabbedPane.setTitleAt(8, multilingualAnwender.toString());

    setLanguage(KEY.ADMINISTRATOR, code); // der neue Name wird gesetzt
    treeView(code);

    domain.setLanguage(code);
    mailserver.setLanguage(code);
    forum.setLanguage(code);
    chatfilter.setLanguage(code);
    antraegeVerwalten.setLanguage(code);
    versionen.setLanguage(code);
    spitzname.setLanguage(code);
    anwender.setLanguage(code);
    chatmodul.setLanguage(code);
  }



  /**
   * Alle verbotenen Nicknames werden übergeben.
   *
   * @param values
   *               verbotene Nickanmes
   */
  public void setNicknames(List<String> values) {
    spitzname.setNicknames(values);
  }



  public void setRaumfilterliste(List<TransferRoomfilter> value) {
    list.clear();
    value.forEach(transferRoomfilter -> {
      list.add(transferRoomfilter.getRoomfilter());
    });
    chatfilter.setFilterliste(list);
    value.clear();
  }



  @Override
  public void setType(Frames value) {

  }



  /**
   * Alle veralteten Programmversionen werden übergeben.
   *
   * @param outdated
   *                 veraltete Versionen
   */
  public void setVeralteteProgrammversionen(List<String> outdated) {
    versionen.setVersionen(outdated);
  }



  void testmail() {
    config = transfer();
    try {
      config.setMailSmtpPort(mailserver.getPort());
      changes.firePropertyChange(AdministratorFrame.class.getName(), Control.NULL, Control.TESTMAIL);
    }
    catch (StringException e) {
      JOptionPane.showMessageDialog(
          AdministratorFrame.this,
          "<html>" + "Der <b><span style=\"color:red\">Port</span></b> muss ein Zahlenwert sein." + "</html>",
          "Testmail fehlgeschlagen", JOptionPane.ERROR_MESSAGE
      );
    }
  }



  private TransferConfig transfer() {
    config = new TransferConfig();
    config.setIsPublic(domain.getIsPublic());
    config.setDomain(domain.getDomain());
    config.setMailSmtpHost(mailserver.getHost());
    config.setMailSmtpUser(mailserver.getBenutzername());
    return config;
  }

}
