/*
 * Copyright (C) 2015 Square, 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 keywhiz.service.daos;

import com.google.common.collect.ImmutableMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import keywhiz.api.model.SanitizedSecret;
import keywhiz.api.model.Secret;
import keywhiz.service.crypto.ContentCryptographer;
import keywhiz.service.crypto.SecretTransformer;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.stream.Collectors.toList;

public class SecretController {
  private final SecretTransformer transformer;
  private final ContentCryptographer cryptographer;
  private final SecretDAO secretDAO;

  public SecretController(SecretTransformer transformer, ContentCryptographer cryptographer,
      SecretDAO secretDAO) {
    this.transformer = transformer;
    this.cryptographer = cryptographer;
    this.secretDAO = secretDAO;
  }

  /**
   * @param secretId external secret series id to look up secrets by.
   * @return all Secrets with given id. May be empty or include multiple versions.
   */
  public List<Secret> getSecretsById(long secretId) {
    return transformer.transform(secretDAO.getSecretsById(secretId));
  }

  /**
   * @param secretId external secret series id to look up secrets by.
   * @param version specific version of secret. May be empty.
   * @return Secret matching input parameters or Optional.absent().
   */
  public Optional<Secret> getSecretByIdAndVersion(long secretId, String version) {
    return secretDAO.getSecretByIdAndVersion(secretId, version).map(transformer::transform);
  }

  /**
   * @param name of secret series to look up secrets by.
   * @param version specific version of secret. May be empty.
   * @return Secret matching input parameters or Optional.absent().
   */
  public Optional<Secret> getSecretByNameAndVersion(String name, String version) {
    return secretDAO.getSecretByNameAndVersion(name, version).map(transformer::transform);
  }

  /** @return all existing sanitized secrets. */
  public List<SanitizedSecret> getSanitizedSecrets() {
    return secretDAO.getSecrets().stream()
        .map(SanitizedSecret::fromSecretSeriesAndContent)
        .collect(toList());
  }

  /** @return all existing sanitized secrets. */
  public List<SanitizedSecret> getSecretsNameOnly() {
    return secretDAO.getSecretsNameOnly()
        .stream()
        .map(s -> SanitizedSecret.of(s.getKey(), s.getValue()))
        .collect(toList());
  }

  /** @return all versions for this secret name. */
  public List<String> getVersionsForName(String name) {
    checkArgument(!name.isEmpty());
    return secretDAO.getVersionsForSecretName(name);
  }

  public SecretBuilder builder(String name, String secret, String creator, long expiry) {
    checkArgument(!name.isEmpty());
    checkArgument(!secret.isEmpty());
    checkArgument(!creator.isEmpty());
    String encryptedSecret = cryptographer.encryptionKeyDerivedFrom(name).encrypt(secret);
    return new SecretBuilder(transformer, secretDAO, name, encryptedSecret, creator, expiry);
  }

  /** Builder to generate new secret series or versions with. */
  public static class SecretBuilder {
    private final SecretTransformer transformer;
    private final SecretDAO secretDAO;
    private final String name;
    private final String encryptedSecret;
    private final String creator;
    private String description = "";
    private Map<String, String> metadata = ImmutableMap.of();
    private long expiry = 0;
    private String version = "";
    private String type;
    private Map<String, String> generationOptions = ImmutableMap.of();

    /**
     * @param transformer
     * @param secretDAO
     * @param name of secret series.
     * @param encryptedSecret encrypted content of secret version
     * @param creator username responsible for creating this secret version.
     */
    private SecretBuilder(SecretTransformer transformer, SecretDAO secretDAO, String name, String encryptedSecret,
        String creator, long expiry) {
      this.transformer = transformer;
      this.secretDAO = secretDAO;
      this.name = name;
      this.encryptedSecret = encryptedSecret;
      this.creator = creator;
      this.expiry = expiry;
    }

    /**
     * Supply an optional description of the secret.
     * @param description description of secret
     * @return the builder
     */
    public SecretBuilder withDescription(String description) {
      this.description = checkNotNull(description);
      return this;
    }

    /**
     * Supply optional map of metadata properties for the secret.
     * @param metadata metadata of secret
     * @return the builder
     */
    public SecretBuilder withMetadata(Map<String, String> metadata) {
      this.metadata = checkNotNull(metadata);
      return this;
    }

    /**
     * Supply an optional version of the secret, otherwise the default '' is used.
     * @param version version of secret
     * @return the builder
     */
    public SecretBuilder withVersion(String version) {
      this.version = checkNotNull(version);
      return this;
    }

    /**
     * Supply a secret type, otherwise the default '' is used.
     * @param type type of secret
     * @return the builder
     */
    public SecretBuilder withType(String type) {
      this.type = checkNotNull(type);
      return this;
    }

    /**
     * Supply a map of options used to generate the secret.
     * @param generationOptions map of settings from the generator to persist
     * @return the builder
     */
    public SecretBuilder withGenerationOptions(Map<String, String> generationOptions) {
      this.generationOptions = checkNotNull(generationOptions);
      return this;
    }

    /**
     * Finalizes creation of a new secret.
     *
     * @return an instance of the newly created secret.
     */
    public Secret build() {
        secretDAO.createSecret(name, encryptedSecret, version, creator, metadata, expiry, description, type,
            generationOptions);
        return transformer.transform(secretDAO.getSecretByNameAndVersion(name, version).get());
    }
  }
}

@@ -4096,41 +4096,8 @@
  0;%0A
-    private String version = %22%22;%0A
     
@@ -5401,859 +5401,209 @@
 ly a
-n optional version of the secret, otherwise the default '' is used.%0A     * @param version version of secret%0A     * @return the builder%0A     */%0A    public SecretBuilder withVersion(String version) %7B%0A      this.version = checkNotNull(version);%0A      return this;%0A    %7D%0A%0A    /**%0A     * Supply a secret type, otherwise the default '' is used.%0A     * @param type type of secret%0A     * @return the builder%0A     */%0A    public SecretBuilder withType(String type) %7B%0A      this.type = checkNotNull(type);%0A      return this;%0A    %7D%0A%0A    /**%0A     * Supply a map of options used to generate the secret.%0A     * @param generationOptions map of settings from the generator to persist%0A     * @return the builder%0A     */%0A    public SecretBuilder withGenerationOptions(Map%3CString, String%3E generationOptions) %7B%0A      this.generationOptions = checkNotNull(generationOptions
+ secret type, otherwise the default '' is used.%0A     * @param type type of secret%0A     * @return the builder%0A     */%0A    public SecretBuilder withType(String type) %7B%0A      this.type = checkNotNull(type
 );%0A 
@@ -5831,23 +5831,18 @@
 Secret, 
-version
+%22%22
 , creato
@@ -5992,23 +5992,18 @@
 n(name, 
-version
+%22%22
 ).get())

Delete SecretController.withVersion