/*
 * Copyright 2008 Google Inc.
 *
 * 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 com.google.gwt.core.ext.linker;

import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.thirdparty.guava.common.hash.Hashing;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Locale;

/**
 * Provides basic functions common to all Linker implementations.
 */
public abstract class AbstractLinker extends Linker {
  /**
   * A helper method to create an artifact from an array of bytes.
   *
   * @param logger a TreeLogger
   * @param what the data to emit
   * @param partialPath the partial path of the resource
   * @return an artifact that contains the given data
   * @throws UnableToCompleteException
   */
  protected final SyntheticArtifact emitBytes(TreeLogger logger, byte[] what,
      String partialPath) throws UnableToCompleteException {
    return new SyntheticArtifact(getClass(), partialPath, what);
  }

  /**
   * A helper method to create an artifact from an array of bytes.
   *
   * @param logger a TreeLogger
   * @param what the data to emit
   * @param partialPath the partial path of the resource
   * @return an artifact that contains the given data
   * @param lastModified the last modified time of the new artifact
   * @throws UnableToCompleteException
   */
  protected final SyntheticArtifact emitBytes(TreeLogger logger, byte[] what,
      String partialPath, long lastModified) throws UnableToCompleteException {
    return new SyntheticArtifact(getClass(), partialPath, what, lastModified);
  }

  /**
   * A helper method to create an artifact to emit the contents of an
   * InputStream.
   *
   * @param logger a TreeLogger
   * @param what the source InputStream
   * @param partialPath the partial path of the emitted resource
   * @return an artifact that contains the contents of the InputStream
   */
  protected final SyntheticArtifact emitInputStream(TreeLogger logger,
      InputStream what, String partialPath) throws UnableToCompleteException {
    try (what) {
      return emitBytes(logger, what.readAllBytes(), partialPath);
    } catch (IOException e) {
      logger.log(TreeLogger.ERROR, "Error during copy", e);
      throw new UnableToCompleteException();
    }
  }

  /**
   * A helper method to create an artifact to emit the contents of an
   * InputStream.
   *
   * @param logger a TreeLogger
   * @param what the source InputStream
   * @param partialPath the partial path of the emitted resource
   * @param lastModified the last modified time of the new artifact
   * @return an artifact that contains the contents of the InputStream
   */
  protected final SyntheticArtifact emitInputStream(TreeLogger logger,
      InputStream what, String partialPath, long lastModified)
      throws UnableToCompleteException {
    try (what) {
      return emitBytes(logger, what.readAllBytes(), partialPath, lastModified);
    } catch (IOException e) {
      logger.log(TreeLogger.ERROR, "Error during copy", e);
      throw new UnableToCompleteException();
    }
  }

  /**
   * A helper method to create an artifact to emit a String.
   *
   * @param logger a TreeLogger
   * @param what the contents of the Artifact to emit
   * @param partialPath the partial path of the emitted resource
   * @return an artifact that contains the contents of the given String
   */
  protected final SyntheticArtifact emitString(TreeLogger logger, String what,
      String partialPath) throws UnableToCompleteException {
    return emitBytes(logger, what.getBytes(StandardCharsets.UTF_8), partialPath);
  }

  /**
   * A helper method to create an artifact to emit a String.
   *
   * @param logger a TreeLogger
   * @param what the contents of the Artifact to emit
   * @param partialPath the partial path of the emitted resource
   * @param lastModified the last modified time of the new artifact
   * @return an artifact that contains the contents of the given String
   */
  protected final SyntheticArtifact emitString(TreeLogger logger, String what,
      String partialPath, long lastModified) throws UnableToCompleteException {
    return emitBytes(logger, what.getBytes(StandardCharsets.UTF_8), partialPath, lastModified);
  }

  /**
   * A helper method to create an artifact from an array of bytes with a strong
   * name.
   *
   * @param logger a TreeLogger
   * @param what the data to emit
   * @param prefix a non-null string to prepend to the hash to determine the
   *          Artifact's partial path
   * @param suffix a non-null string to append to the hash to determine the
   *          Artifact's partial path
   * @return an artifact that contains the given data
   */
  protected final SyntheticArtifact emitWithStrongName(TreeLogger logger,
      byte[] what, String prefix, String suffix)
      throws UnableToCompleteException {
    String hash = Hashing.murmur3_128().hashBytes(what).toString().toUpperCase(Locale.ROOT);
    String strongName = prefix + hash + suffix;
    return emitBytes(logger, what, strongName);
  }

  /**
   * A helper method to create an artifact from an array of bytes with a strong
   * name.
   *
   * @param logger a TreeLogger
   * @param what the data to emit
   * @param prefix a non-null string to prepend to the hash to determine the
   *          Artifact's partial path
   * @param suffix a non-null string to append to the hash to determine the
   *          Artifact's partial path
   * @param lastModified the last modified time of the new artifact
   * @return an artifact that contains the given data
   */
  protected final SyntheticArtifact emitWithStrongName(TreeLogger logger,
      byte[] what, String prefix, String suffix, long lastModified)
      throws UnableToCompleteException {
    String hash = Hashing.murmur3_128().hashBytes(what).toString().toUpperCase(Locale.ROOT);
    String strongName = prefix + hash + suffix;
    return emitBytes(logger, what, strongName, lastModified);
  }
}
