// Copyright (C) 2009 The Android Open Source Project
//
// 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.gerrit.server.mail;

import com.google.gerrit.common.data.ParameterizedString;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;

/** Creates a {@link FromAddressGenerator} from the {@link GerritServerConfig} */
@Singleton
public class FromAddressGeneratorProvider implements
    Provider<FromAddressGenerator> {
  private final FromAddressGenerator generator;

  @Inject
  FromAddressGeneratorProvider(@GerritServerConfig final Config cfg,
      final @AnonymousCowardName String anonymousCowardName,
      @GerritPersonIdent final PersonIdent myIdent,
      final AccountCache accountCache) {

    final String from = cfg.getString("sendemail", null, "from");
    final Address srvAddr = toAddress(myIdent);

    if (from == null || "MIXED".equalsIgnoreCase(from)) {
      ParameterizedString name = new ParameterizedString("${user} (Code Review)");
      generator =
          new PatternGen(srvAddr, accountCache, anonymousCowardName, name,
              srvAddr.email);

    } else if ("USER".equalsIgnoreCase(from)) {
      generator = new UserGen(accountCache, srvAddr);

    } else if ("SERVER".equalsIgnoreCase(from)) {
      generator = new ServerGen(srvAddr);

    } else {
      final Address a = Address.parse(from);
      final ParameterizedString name = a.name != null ? new ParameterizedString(a.name) : null;
      if (name == null || name.getParameterNames().isEmpty()) {
        generator = new ServerGen(a);
      } else {
        generator =
            new PatternGen(srvAddr, accountCache, anonymousCowardName, name,
                a.email);
      }
    }
  }

  private static Address toAddress(final PersonIdent myIdent) {
    return new Address(myIdent.getName(), myIdent.getEmailAddress());
  }

  @Override
  public FromAddressGenerator get() {
    return generator;
  }

  static final class UserGen implements FromAddressGenerator {
    private final AccountCache accountCache;
    private final Address srvAddr;

    UserGen(AccountCache accountCache, Address srvAddr) {
      this.accountCache = accountCache;
      this.srvAddr = srvAddr;
    }

    @Override
    public boolean isGenericAddress(Account.Id fromId) {
      return false;
    }

    @Override
    public Address from(final Account.Id fromId) {
      if (fromId != null) {
        final Account a = accountCache.get(fromId).getAccount();
        if (a.getPreferredEmail() != null) {
          return new Address(a.getFullName(), a.getPreferredEmail());
        }
      }
      return srvAddr;
    }
  }

  static final class ServerGen implements FromAddressGenerator {
    private final Address srvAddr;

    ServerGen(Address srvAddr) {
      this.srvAddr = srvAddr;
    }

    @Override
    public boolean isGenericAddress(Account.Id fromId) {
      return true;
    }

    @Override
    public Address from(final Account.Id fromId) {
      return srvAddr;
    }
  }

  static final class PatternGen implements FromAddressGenerator {
    private final String senderEmail;
    private final Address serverAddress;
    private final AccountCache accountCache;
    private final String anonymousCowardName;
    private final ParameterizedString namePattern;

    PatternGen(final Address serverAddress, final AccountCache accountCache,
        final String anonymousCowardName,
        final ParameterizedString namePattern, final String senderEmail) {
      this.senderEmail = senderEmail;
      this.serverAddress = serverAddress;
      this.accountCache = accountCache;
      this.anonymousCowardName = anonymousCowardName;
      this.namePattern = namePattern;
    }

    @Override
    public boolean isGenericAddress(Account.Id fromId) {
      return false;
    }

    @Override
    public Address from(final Account.Id fromId) {
      final String senderName;

      if (fromId != null) {
        final Account account = accountCache.get(fromId).getAccount();
        String fullName = account.getFullName();
        if (fullName == null || "".equals(fullName)) {
          fullName = anonymousCowardName;
        }
        senderName = namePattern.replace("user", fullName).toString();

      } else {
        senderName = serverAddress.name;
      }

      return new Address(senderName, senderEmail);
    }
  }
}

@@ -642,16 +642,56 @@
 .mail;%0A%0A
+import com.google.common.base.Charsets;%0A
 import c
@@ -1119,16 +1119,63 @@
 leton;%0A%0A
+import org.apache.commons.codec.binary.Base64;%0A
 import o
@@ -1244,16 +1244,100 @@
 Ident;%0A%0A
+import java.security.MessageDigest;%0Aimport java.security.NoSuchAlgorithmException;%0A%0A
 /** Crea
@@ -4146,24 +4146,37 @@
 ivate final 
+Parameterized
 String sende
@@ -4177,24 +4177,31 @@
  senderEmail
+Pattern
 ;%0A    privat
@@ -4590,19 +4590,50 @@
 derEmail
- = 
+Pattern = new ParameterizedString(
 senderEm
@@ -4635,16 +4635,17 @@
 derEmail
+)
 ;%0A      
@@ -5416,50 +5416,685 @@
     
-return new Address(senderName, senderEmail
+String senderEmail;%0A      if (senderEmailPattern.getParameterNames().isEmpty()) %7B%0A        senderEmail = senderEmailPattern.getRawPattern();%0A      %7D else %7B%0A        senderEmail = senderEmailPattern%0A            .replace(%22userHash%22, hashOf(senderName))%0A            .toString();%0A      %7D%0A      return new Address(senderName, senderEmail);%0A    %7D%0A  %7D%0A%0A  private static String hashOf(String data) %7B%0A    try %7B%0A      MessageDigest hash = MessageDigest.getInstance(%22MD5%22);%0A      byte%5B%5D bytes = hash.digest(data.getBytes(Charsets.UTF_8));%0A      return Base64.encodeBase64URLSafeString(bytes);%0A    %7D catch (NoSuchAlgorithmException e) %7B%0A      throw new RuntimeException(%22No MD5 available%22, e
 );%0A 

Allow unique from address generation.