/*
 * Copyright (c) 2009, Takeyuki Nagao
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the
 * following conditions are met:
 * 
 *  * Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *    
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */
package dvi.image.split;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import dvi.DviException;
import dvi.DviRect;
import dvi.DviRectSplitter;
import dvi.DviResolution;
import dvi.DviSize;
import dvi.util.DviUtils;

public class ZipSplitImageReader {
  private static final Logger LOGGER = Logger
      .getLogger(ZipSplitImageReader.class.getName());
  private final File file;
  
  private static class SplitImageImpl implements SplitImage
  {
    private DviRectSplitter rectSplitter;
    private final ArrayList<SplitPiece> pieces = new ArrayList<SplitPiece>();
    private final File file;
    private final Properties props;
    private final DviResolution res;
    
    public SplitImageImpl(File file, Properties props, DviResolution res, DviRectSplitter rectSplitter)
    {
      this.file = file;
      this.props = props;
      this.res = res;
      this.rectSplitter = rectSplitter;
    }

    public Collection<SplitPiece> getPieces() throws DviException {
      return Collections.unmodifiableCollection(pieces);
    }

    public DviRectSplitter getRectSplitter() throws DviException {
      return rectSplitter;
    }

    public Iterator<SplitPiece> iterator() {
      return pieces.iterator();
    }

    public Properties getProperties() {
      return props;
    }

    public DviRect getRect() throws DviException {
      return rectSplitter.getRect();
    }

    public DviResolution getResolution() {
      return res;
    }

    public File getFile() {
      return file;
    }
  }
  
  public ZipSplitImageReader(File file)
  {
    this.file = file;
  }

  public SplitImage getSplitImage() throws DviException
  {
    try {
      ZipFile zipFile = new ZipFile(file);
      try {
        String indexEntryName = "images/index.properties";
        ZipEntry entry = zipFile.getEntry(indexEntryName);
        if (entry == null) {
          throw new DviException("Image bundle has no index file: " + file.getAbsolutePath());
        }
        Properties props = new Properties();
        props.load(zipFile.getInputStream(entry));
        String fmt = props.getProperty("image.format.name");
        if ("image-bundle".equals(fmt)) {
          final int dpi = Integer.parseInt(props.getProperty("image.hres.dpi"));
          final int sf = Integer.parseInt(props.getProperty("image.hres.sf"));
          final int width = Integer.parseInt(props.getProperty("image.total.width")); 
          final int height = Integer.parseInt(props.getProperty("image.total.height")); 
          final int uw = Integer.parseInt(props.getProperty("image.unit.width")); 
          final int uh = Integer.parseInt(props.getProperty("image.unit.height")); 
          final DviResolution res = new DviResolution(dpi, sf);
          final DviSize unitSize = new DviSize(uw, uh);
          final DviRect rect = new DviRect(0, 0, width, height);
          final DviRectSplitter rectSplitter = new DviRectSplitter(rect, unitSize);
          SplitImageImpl splitImage = new SplitImageImpl(file, props, res, rectSplitter);
          { // populate the image with pieces.
            int rows = rectSplitter.getNumRows();
            int cols = rectSplitter.getNumColumns();
            for (int i=0; i<rows; i++) {
              for (int j=0; j<cols; j++) {
                String entryName = props.getProperty("image.piece." + i + "." + j + ".file");
                ZipImagePiece piece = new ZipImagePiece(splitImage, file, entryName, res, rectSplitter, i, j);
                splitImage.pieces.add(piece);
              }
            }
          }
          return splitImage;
        } else {
          throw new DviException("Unrecognized format " + fmt + " in index file: " + indexEntryName + " of " + file.getAbsolutePath());
        }
      } finally {
        zipFile.close();
      }
    } catch (MalformedURLException e) {
      DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
      throw new DviException(e);
    } catch (IOException e) {
      DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
      throw new DviException(e);
    }
  }

  public File getFile() {
    return file;
  }
}
