/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

package plugins;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import ilog.views.IlvManagerView;
import ilog.views.maps.IlvMapUtil;
import ilog.views.maps.datasource.IlvMapDataSource;
import ilog.views.maps.format.cadrg.IlvCADRGCoverage;
import ilog.views.maps.format.cadrg.IlvCADRGFrame;
import ilog.views.maps.format.cadrg.IlvCADRGTocReader;
import ilog.views.maps.raster.IlvRasterAbstractReader;
import ilog.views.maps.raster.datasource.IlvRasterDataSourceFactory;
import ilog.views.maps.raster.datasource.IlvThreadMonitoringData;
import ilog.views.maps.theme.IlvMapStyleController;
import ilog.views.maps.theme.IlvMapStyleControllerProperty;
import nodefense.CADRGDefLess;

/**
 * Class that manages CADRG import action.
 */
public class CADRGLoadAction extends ImportAction {
  class CADRGEnumeration implements Enumeration<IlvMapDataSource> {
    int ns;
    final Object[] ids;
    Integer[] scales;
    Object covs;
    double basePct;

    // CADRGEnumeration(String[] monitorID,IlvCADRGCoverageList covs)
    CADRGEnumeration(Object[] ids, Object covs) {
      this.scales = CADRGDefLess.getOrderedScaleList(covs);
      // this.scales=covs.getOrderedScaleList();
      this.ids = ids;
      this.covs = covs;
      basePct = 100.0 / (scales.length + 1);
      ns = 0;
    }

    /**
     * @see java.util.Enumeration#hasMoreElements()
     */
    Override
    public boolean hasMoreElements() {
      boolean hasMore = false;
      for (int i = ns; i < scales.length; i++) {
        if (scaleSelection[scales.length - 1 - i].isSelected()) {
          hasMore = true;
          break;
        }
      }
      if (!hasMore) {
        setAdvancement(RENDERING, ids, 100);
      }
      return hasMore;
    }

    /**
     * @see java.util.Enumeration#nextElement()
     */
    Override
    public IlvMapDataSource nextElement() {
      if (hasMoreElements()) {
        IlvMapStyleController themeControl = IlvMapStyleControllerProperty.GetMapStyleController(view.getManager());
        boolean first = (ns == 0);
        for (; ns < scales.length && !scaleSelection[scales.length - 1 - ns].isSelected(); ns++) {
          // do nothing.
        }
        int i = ns;
        ns++;
        int beg = (int) (basePct * (i + 0.1));
        int mid = (int) (basePct * (i + 0.8));
        int end = (int) (basePct * (i + 1));
        Integer scale = scales[scales.length - 1 - i];
        // IlvCADRGCoverage[] scaleCovs = covs.getCoverageList(scale);
        IlvCADRGCoverage[] scaleCovs = CADRGDefLess.getCoverageList(covs, scale);
        setAdvancement(RENDERING, ids, beg);
        if (scaleCovs.length != 0) {
          IlvRasterAbstractReader frameReader = CADRGDefLess.newIlvRasterCADRGReader();
          // IlvRasterCADRGReader frameReader = new IlvRasterCADRGReader();
          String scaleDesc = scaleCovs[0].getScaleDescription().trim();
          for (int iCov = 0; iCov < scaleCovs.length; iCov++) {
            int b1 = beg;
            int b2 = mid;
            // JV-4334
            if (scaleCovs.length != 1) {
              b1 = (int) (beg + (iCov / (double) (scaleCovs.length - 1)) * (mid - beg));
              b2 = (int) (beg + ((iCov + 1) / (double) (scaleCovs.length - 1)) * (mid - beg));
            }
            setAdvancement(RENDERING, ids, b1);
            IlvCADRGCoverage cov = scaleCovs[iCov];
            int b = 0;
            int nRows = cov.getRows();
            int nCols = cov.getColumns();
            for (int row = 0; row < nRows; row++) {
              for (int column = 0; column < nCols; column++) {
                IlvCADRGFrame f = cov.getFrame(row, column);
                if (f != null) {
                  // frameReader.addCADRGFrame(f);
                  CADRGDefLess.addCADRGFrame(frameReader, f);
                }
                b++;
                setAdvancement(RENDERING, ids, (int) (b1 + (b2 - b1) * (double) b / (nRows * nCols)));
              }
            }
          }
          setAdvancement(RENDERING, ids, mid);
          IlvThreadMonitoringData monitorData = new IlvThreadMonitoringData(getMonitor(), ids,
              scaleDesc + " " + getActivityDescription(RENDERING), //$NON-NLS-1$
              mid, end);
          IlvMapDataSource ds = IlvRasterDataSourceFactory.buildTiledImageDataSource(view.getManager(), frameReader,
              false, true, monitorData);
          ds.setName(getFormatName() + " " + scaleDesc); //$NON-NLS-1$
          ds.getInsertionLayer().setName(ds.getName());

          double tscale = scale.intValue() * 4;
          if (!first) {
            themeControl.addTheme(1d / tscale, ds.getInsertionLayer(),
                IlvMapUtil.getString(CADRGLoadAction.class, "CADRGLoadAction.InvisibleStyleName")); //$NON-NLS-1$
            themeControl.getStyle(ds.getInsertionLayer(), 1d / tscale).setVisibleInView(false);
          }
          if (hasMoreElements()) {
            tscale = scale.intValue() / 4;
            themeControl.addTheme(1d / tscale, ds.getInsertionLayer(),
                IlvMapUtil.getString(CADRGLoadAction.class, "CADRGLoadAction.VisibleStyleName")); //$NON-NLS-1$
            themeControl.getStyle(ds.getInsertionLayer(), 1d / tscale).setVisibleInView(true);
            themeControl.getStyle(ds.getInsertionLayer(), 1).setVisibleInView(false);
          } else {
            if (!first) {
              themeControl.getStyle(ds.getInsertionLayer(), 1).setVisibleInView(true);
            }
          }
          return ds;
        }
      }
      return null;
    }

  }

  /**
   * Creates an action for the specified view
   * 
   * @param view
   *          view to add map data to.
   */
  public CADRGLoadAction(IlvManagerView view) {
    super(view);
  }

  /**
   * @see plugins.ImportAction#getSubDirectory()
   */
  Override
  protected String getSubDirectory() {
    return IlvMapUtil.getString(getClass(), "CADRGLoadAction.CDDirectory"); //$NON-NLS-1$
  }

  private JPanel accessory;
  private JScrollPane accessoryPane;
  private JCheckBox noData;
  private JCheckBox scaleSelection[];

  /**
   * Returns null.
   * 
   * @see plugins.ImportAction#getAccessory()
   */
  Override
  public JComponent getAccessory() {
    if (accessoryPane == null) {
      accessory = new JPanel(new GridBagLayout());
      String msg = IlvMapUtil.getString(CADRGLoadAction.class, "CADRGLoadAction.scaleSelection"); //$NON-NLS-1$
      accessory.setBorder(BorderFactory.createTitledBorder(msg));
      noData = new JCheckBox(msg);
      noData.setEnabled(false);
      accessory.add(noData);
      accessoryPane = new JScrollPane(accessory, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
          ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
      accessory.setBackground(Color.white);
    }
    return accessoryPane;
  }

  /**
   * @see plugins.ImportAction#selectedFileChanged(File)
   */
  Override
  public void selectedFileChanged(File file) {
    getAccessory(); // init accessories components
    accessory.removeAll();
    scaleSelection = new JCheckBox[0];
    if (file != null) {
      try {
        IlvCADRGTocReader tocReader = new IlvCADRGTocReader(file.getPath());
        // Get all coverage info
        Object list = CADRGDefLess.newIlvCADRGCoverageList();
        CADRGDefLess.addCoverages(list, file.getPath(), tocReader.getCoverages());
        String scaleDesc[] = CADRGDefLess.getOrderedScaleDescription(list);
        scaleSelection = new JCheckBox[scaleDesc.length];
        GridBagConstraints c = new GridBagConstraints();
        for (int i = 0; i < scaleDesc.length; i++) {
          scaleSelection[i] = new JCheckBox(scaleDesc[i], true);
          scaleSelection[i].setOpaque(false);
          c.gridy = scaleDesc.length - i;
          c.anchor = GridBagConstraints.LINE_START;
          accessory.add(scaleSelection[i], c);
        }
      } catch (IOException e) {
        // ignore
      }
    }
    if (accessory.getComponentCount() == 0) {
      accessory.add(noData);
    }
    accessoryPane.updateUI();
  }

  /**
   * @see plugins.ImportAction#selectedURLChanged(URL)
   */
  Override
  public void selectedURLChanged(URL url) {
    if (url != null) {
      selectedFileChanged(new File(url.getFile()));
    } else {
      selectedFileChanged(null);
    }
  }

  /**
   * @see plugins.ImportAction#approveSelection(File [])
   */
  Override
  public boolean approveSelection(File selection[]) {
    boolean ok = false;
    if (scaleSelection != null) {
      for (int i = 0; i < scaleSelection.length; i++) {
        if (scaleSelection[i].isSelected()) {
          ok = true;
          break;
        }
      }
    }
    if (!ok) {
      JOptionPane.showMessageDialog(view,
          IlvMapUtil.getString(VMAPLoadAction.class, "CADRGLoadAction.NoSelectionMessage"), //$NON-NLS-1$
          IlvMapUtil.getString(VMAPLoadAction.class, "CADRGLoadAction.NoSelectionTitle"), //$NON-NLS-1$
          JOptionPane.ERROR_MESSAGE);
      return false;
    }
    return super.approveSelection(selection);
  }

  /**
   * @see plugins.ImportAction#getDataSources(java.lang.String[])
   */
  Override
  public Enumeration<IlvMapDataSource> getDataSources(String fileNames[]) throws IOException {
    // IlvCADRGCoverageList covs = new IlvCADRGCoverageList();
    Object covs = CADRGDefLess.newIlvCADRGCoverageList();
    IlvCADRGTocReader readers[] = new IlvCADRGTocReader[fileNames.length];
    for (int i = 0; i < fileNames.length; i++) {
      readers[i] = new IlvCADRGTocReader(fileNames[i]);
      // covs.addCoverages(fileNames[i], readers[i].getCoverages());
      CADRGDefLess.addCoverages(covs, fileNames[i], readers[i].getCoverages());
    }
    return new CADRGEnumeration(fileNames, covs);
  }

  /**
   * @see plugins.ImportAction#getDataSources(URL[])
   */
  Override
  public Enumeration<IlvMapDataSource> getDataSources(URL urls[]) throws IOException {
    // IlvCADRGCoverageList covs = new IlvCADRGCoverageList();
    Object covs = CADRGDefLess.newIlvCADRGCoverageList();
    IlvCADRGTocReader readers[] = new IlvCADRGTocReader[urls.length];
    for (int i = 0; i < urls.length; i++) {
      readers[i] = new IlvCADRGTocReader(urls[i]);
      // covs.addCoverages(fileNames[i], readers[i].getCoverages());
      CADRGDefLess.addCoverages(covs, urls[i], readers[i].getCoverages());
    }
    return new CADRGEnumeration(urls, covs);
  }

  /**
   * @see plugins.ImportAction#getExtensions()
   */
  Override
  public String[] getExtensions() {
    return new String[] { ".toc" }; //$NON-NLS-1$
  }

  /**
   * @see plugins.ImportAction#getFormatName()
   */
  Override
  public String getFormatName() {
    return ilog.views.maps.IlvMapUtil.getString(getClass(), "CADRGLoadAction.FormatName"); //$NON-NLS-1$
  }

  /**
   * @see plugins.ImportAction#isAvailable()
   */
  Override
  public boolean isAvailable() {
    return super.isAvailable() && CADRGDefLess.isAvailable();
  }
}