// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
//
// 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 google.registry.model.domain;

import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;

import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Embed;

import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.rgp.GracePeriodStatus;

import org.joda.time.DateTime;

import javax.annotation.Nullable;

/**
 * A domain grace period with an expiration time.
 *
 * <p>When a grace period expires, it is lazily removed from the {@link DomainResource} the next
 * time the resource is loaded from the datastore.
 */
@Embed
public class GracePeriod extends ImmutableObject {

  /** The type of grace period. */
  GracePeriodStatus type;

  /** When the grace period ends. */
  DateTime expirationTime;

  /** The registrar to bill. */
  String clientId;

  /**
   * The one-time billing event corresponding to the action that triggered this grace period, or
   * null if not applicable.  Not set for autorenew grace periods (which instead use the field
   * {@code billingEventRecurring}) or for redemption grace periods (since deletes have no cost).
   */
  // NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
  Ref<BillingEvent.OneTime> billingEventOneTime = null;

  /**
   * The recurring billing event corresponding to the action that triggered this grace period, if
   * applicable - i.e. if the action was an autorenew - or null in all other cases.
   */
  // NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections.
  Ref<BillingEvent.Recurring> billingEventRecurring = null;

  public GracePeriodStatus getType() {
    // NB: We implicitly convert SUNRUSH_ADD to ADD, since they should be functionally equivalent.
    return type == GracePeriodStatus.SUNRUSH_ADD ? GracePeriodStatus.ADD : type;
  }

  public boolean isSunrushAddGracePeriod() {
    return type == GracePeriodStatus.SUNRUSH_ADD;
  }

  public DateTime getExpirationTime() {
    return expirationTime;
  }

  public String getClientId() {
    return clientId;
  }

  /** Returns true if this GracePeriod has an associated BillingEvent; i.e. if it's refundable. */
  public boolean hasBillingEvent() {
    return billingEventOneTime != null || billingEventRecurring != null;
  }

  /**
   * Returns the one time billing event. The value will only be non-null if the type of this grace
   * period is not AUTO_RENEW.
   */

  public Ref<BillingEvent.OneTime> getOneTimeBillingEvent() {
    return billingEventOneTime;
  }

  /**
   * Returns the recurring billing event. The value will only be non-null if the type of this grace
   * period is AUTO_RENEW.
   */
  public Ref<BillingEvent.Recurring> getRecurringBillingEvent() {
    return billingEventRecurring;
  }

  private static GracePeriod createInternal(
       GracePeriodStatus type,
       DateTime expirationTime,
       String clientId,
       @Nullable Ref<BillingEvent.OneTime> billingEventOneTime,
       @Nullable Ref<BillingEvent.Recurring> billingEventRecurring) {
    checkArgument((billingEventOneTime == null) || (billingEventRecurring == null),
        "A grace period can have at most one billing event");
    checkArgument((billingEventRecurring != null) == (GracePeriodStatus.AUTO_RENEW.equals(type)),
        "Recurring billing events must be present on (and only on) autorenew grace periods");
    GracePeriod instance = new GracePeriod();
    instance.type = checkArgumentNotNull(type);
    instance.expirationTime = checkArgumentNotNull(expirationTime);
    instance.clientId = checkArgumentNotNull(clientId);
    instance.billingEventOneTime = billingEventOneTime;
    instance.billingEventRecurring = billingEventRecurring;
    return instance;
  }

  /** Create a GracePeriod for an (optional) OneTime billing event.
   *
   * <p>Normal callers should always use {@link #forBillingEvent} instead, assuming they do not
   * need to avoid loading the BillingEvent from datastore.  This method should typically be
   * called only from test code to explicitly construct GracePeriods.
   */
  public static GracePeriod create(
      GracePeriodStatus type,
      DateTime expirationTime,
      String clientId,
      @Nullable Ref<BillingEvent.OneTime> billingEventOneTime) {
    return createInternal(type, expirationTime, clientId, billingEventOneTime, null);
  }

  /** Create a GracePeriod for a Recurring billing event. */
  public static GracePeriod createForRecurring(
      GracePeriodStatus type,
      DateTime expirationTime,
      String clientId,
      Ref<BillingEvent.Recurring> billingEventRecurring) {
    checkArgumentNotNull(billingEventRecurring);
    return createInternal(type, expirationTime, clientId, null, billingEventRecurring);
  }

  /** Create a GracePeriod with no billing event. */
  public static GracePeriod createWithoutBillingEvent(
      GracePeriodStatus type, DateTime expirationTime, String clientId) {
    return createInternal(type, expirationTime, clientId, null, null);
  }

  /** Constructs a GracePeriod of the given type from the provided one-time BillingEvent. */
  public static GracePeriod forBillingEvent(
      GracePeriodStatus type, BillingEvent.OneTime billingEvent) {
    return create(
        type, billingEvent.getBillingTime(), billingEvent.getClientId(), Ref.create(billingEvent));
  }
}

@@ -4455,38 +4455,45 @@
 nce;%0A  %7D%0A%0A  /** 
+%0A   * 
 Create
+s
  a GracePeriod f
@@ -5082,32 +5082,33 @@
  %7D%0A%0A  /** Create
+s
  a GracePeriod f
@@ -5485,16 +5485,17 @@
 * Create
+s
  a Grace

Comment typo of the day