/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jetbrains.buildServer.clouds.vmware.client;

import com.intellij.openapi.diagnostic.Logger;
import com.thoughtworks.xstream.XStream;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import jetbrains.buildServer.clouds.vmware.settings.VMImageInfo;
import jetbrains.buildServer.clouds.vmware.vmrun.local.LocalImagesStore;
import jetbrains.buildServer.messages.XStreamHolder;
import jetbrains.buildServer.util.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * @author Eugene Petrenko
 *         Created: 10.12.2009 11:00:28
 */
public class ImagesStore implements LocalImagesStore {
  private static final Logger LOG = Logger.getInstance(ImagesStore.class.getName());

  private final File myHome;
  private final XStreamHolder myHolder;
  private final Map<String, VMImageInfo> myImages = new ConcurrentHashMap<String, VMImageInfo>();

  public ImagesStore(final Configration config, final XStreamHolder holder) {
    myHome = config.getVMStoreHome();
    myHolder = holder;
    scan();
  }

  private void scan() {
    File[] files = myHome.listFiles(new FileFilter() {
      public boolean accept(final File pathname) {
        return pathname.isFile() && pathname.getName().endsWith("image-info.xml");
      }
    });
    if (files == null) return;

    final XStream xs = myHolder.getXStream(getClass().getClassLoader());
    try {
      for (File file : files) {
        try {
          InputStream fis = new BufferedInputStream(new FileInputStream(file));
          VMImageInfo info = (VMImageInfo)xs.fromXML(fis);
          if (info != null) {
            myImages.put(info.getId(), info.resolvePath(file.getParentFile()));
          }
          fis.close();
        } catch (Exception e) {
          LOG.warn("Failed to read: " + file + ". " + e.getMessage(), e);
        }
      }
    } finally {
      myHolder.releaseXStream(xs);
    }
  }

  @NotNull
  public Collection<VMImageInfo> getLocalImages() {
    return new ArrayList<VMImageInfo>(myImages.values());
  }

  @Nullable
  public VMImageInfo mapImage(@NotNull final VMImageInfo img) {
    final VMImageInfo imageInfo = myImages.get(img.getId());
    if (imageInfo != null) return imageInfo;

    createTemplateDir(img);

    return null;
  }

  private File getImageInfoFile(final VMImageInfo img, boolean temp) {
    final String namePrefix = FileUtil.fixDirectoryName(img.getId());
    return new File(myHome, namePrefix + "-image-info.xml" + (temp ? ".tmp" : ""));
  }

  private File createTemplateDir(final VMImageInfo img) {
    final String namePrefix = FileUtil.fixDirectoryName(img.getId());
    final File dest = new File(myHome, namePrefix);

    //noinspection ResultOfMethodCallIgnored
    dest.mkdirs();

    writeImageInfoFile(img, true);
    return dest;
  }

  private void writeImageInfoFile(final VMImageInfo img, final boolean temp) {
    try {
      File info = getImageInfoFile(img, temp);
      OutputStream os = new BufferedOutputStream(new FileOutputStream(info));
      final XStream xs = myHolder.getXStream(getClass().getClassLoader());
      xs.toXML(img, os);
      os.close();
    } catch (IOException e) {
      LOG.info("Failed to create download template info");
    }
  }
}
