/* $Id: MetaDataFactory.java 4509 2008-11-20 22:37:52Z swampwallaby $
 *
 * Copyright (c) 2008 by Brent Easton and Joel Uckelman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available
 * at http://www.opensource.org.
 */
package VASSAL.build.module.metadata;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import VASSAL.build.GameModule;
import VASSAL.build.module.GameState;
import VASSAL.tools.imports.ImportAction;
import VASSAL.tools.io.IOUtils;
import VASSAL.tools.logging.Logger;

public class MetaDataFactory {

  protected static final String BUILDFILE_MODULE_ELEMENT1 = "VASSAL.launch.BasicModule";
  protected static final String BUILDFILE_MODULE_ELEMENT2 = "VASSAL.build.GameModule";
  protected static final String BUILDFILE_EXTENSION_ELEMENT = "VASSAL.build.module.ModuleExtension";

  /**
   * Factory method to build and return an appropriate MetaData class based on
   * the contents of the file. Return null if the file is not a Zip archive, or
   * it is not a VASSAL Module, Extension or Save Game.
   * 
   * @param file
   *          metadata file
   * @return MetaData object
   */
  public static AbstractMetaData buildMetaData(File file) {

    // Check the file exists and is a file
    if (!file.exists() || !file.isFile())
      return null;

    ZipFile zip = null;
    try {
      // Check it is a Zip file
      zip = new ZipFile(file);

      // Check if it is a Save Game file
      ZipEntry entry = zip.getEntry(GameState.SAVEFILE_ZIP_ENTRY);
      if (entry != null) {
        return new SaveMetaData(zip);
      }

      // Check if it has a buildFile
      ZipEntry buildFileEntry = zip.getEntry(GameModule.BUILDFILE);
      if (buildFileEntry == null) {
        return null;
      }

      // It's either a module or an Extension, check for existence of metadata
      entry = zip.getEntry(ExtensionMetaData.ZIP_ENTRY_NAME);
      if (entry != null) {
        return new ExtensionMetaData(zip);
      }

      entry = zip.getEntry(ModuleMetaData.ZIP_ENTRY_NAME);
      if (entry != null) {
        return new ModuleMetaData(zip);
      }

      // read the first few lines of the buildFile
      BufferedReader br = null;
      try {
        br = new BufferedReader(new InputStreamReader(zip
            .getInputStream(buildFileEntry)));
        for (int i = 0; i < 10; i++) {
          final String s = br.readLine();
          if (s.indexOf(BUILDFILE_MODULE_ELEMENT1) > 0
              || s.indexOf(BUILDFILE_MODULE_ELEMENT2) > 0) {
            br.close();
            return new ModuleMetaData(zip);
          }
          else if (s.indexOf(BUILDFILE_EXTENSION_ELEMENT) > 0) {
            br.close();
            return new ExtensionMetaData(zip);
          }
        }
        br.close();
      }
      finally {
        IOUtils.closeQuietly(br);
      }

      zip.close();
    }
    catch (ZipException e) {
      // It is not a Zip file, check for an Importable file
      return ImportAction.buildMetaData(file);
    }
    catch (IOException e) {
      Logger.log(e);
    }
    finally {
      IOUtils.closeQuietly(zip);
    }

    return null;
  }
}
