/*
 * Copyright 2014-present Facebook, 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.facebook.buck.rules.coercer;

import com.facebook.buck.rules.SourcePath;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

import java.util.Objects;

import javax.annotation.Nullable;

/**
 * Simple type representing an iOS or OS X source entry, which can be either:
 *
 *   <ul>
 *     <li>A {@link SourcePath}, or</li>
 *     <li>A {@link SourcePath} plus compiler flags, or</li>
 *     <li>A "source group" (a group name and one or more AppleSource objects)</li>
 *   </ul>
 */
public class AppleSource {
  /**
   * The type of source entry this object represents.
   */
  public enum Type {
      /**
       * A single {@link SourcePath}.
       */
      SOURCE_PATH,
      /**
       * A {@link SourcePath} with compiler flags.
       */
      SOURCE_PATH_WITH_FLAGS,
      /**
       * A source group (group name and one or more AppleSource objects).
       */
      SOURCE_GROUP
  };

  private final Type type;
  @Nullable private final SourcePath sourcePath;
  @Nullable private final Pair<SourcePath, String> sourcePathWithFlags;
  @Nullable private final Pair<String, ImmutableList<AppleSource>> sourceGroup;

  private AppleSource(
      Type type,
      @Nullable SourcePath sourcePath,
      @Nullable Pair<SourcePath, String> sourcePathWithFlags,
      @Nullable Pair<String, ImmutableList<AppleSource>> sourceGroup) {
    this.type = Preconditions.checkNotNull(type);
    Preconditions.checkState(
        sourcePath != null || sourcePathWithFlags != null || sourceGroup != null,
        "At least one of sourcePath, sourcePathWithFlags, or sourceGroup must be non-null");
    if (sourcePath != null) {
      Preconditions.checkState(
          sourcePathWithFlags == null && sourceGroup == null,
          "If sourcePath is non-null, sourcePathWithFlags and sourceGroup must be null");
    }
    if (sourcePathWithFlags != null) {
      Preconditions.checkState(
          sourcePath == null && sourceGroup == null,
          "If sourcePathWithFlags is non-null, sourcePath and sourceGroup must be null");
    }
    if (sourceGroup != null) {
      Preconditions.checkState(
          sourcePath == null && sourcePathWithFlags == null,
          "If sourceGroup is non-null, sourcePath and sourcePathWithFlags must be null");
    }
    this.sourcePath = sourcePath;
    this.sourcePathWithFlags = sourcePathWithFlags;
    this.sourceGroup = sourceGroup;
  }

  /**
   * Gets the type of source entry this object represents.
   */
  public Type getType() {
    return type;
  }

  /**
   * If getType() returns SOURCE_PATH, returns the source path this entry represents.
   * Otherwise, raises an exception.
   */
  public SourcePath getSourcePath() {
    return Preconditions.checkNotNull(sourcePath);
  }

  /**
   * If getType() returns SOURCE_PATH_WITH_FLAGS, returns the (source
   * path, flags) pair this entry represents.  Otherwise, raises an
   * exception.
   */
  public Pair<SourcePath, String> getSourcePathWithFlags() {
    return Preconditions.checkNotNull(sourcePathWithFlags);
  }

  /**
   * If getType() returns SOURCE_GROUP, returns the source group this
   * entry represents. Otherwise, raises an exception.
   */
  public Pair<String, ImmutableList<AppleSource>> getSourceGroup() {
    return Preconditions.checkNotNull(sourceGroup);
  }

  /**
   * Creates an {@link AppleSource} given a {@link SourcePath}.
   */
  public static AppleSource ofSourcePath(SourcePath sourcePath) {
    return new AppleSource(Type.SOURCE_GROUP, sourcePath, null, null);
  }

  /**
   * Creates an {@link AppleSource} given a ({@link SourcePath}, flags) pair.
   */
  public static AppleSource ofSourcePathWithFlags(Pair<SourcePath, String> sourcePathWithFlags) {
    return new AppleSource(Type.SOURCE_PATH_WITH_FLAGS, null, sourcePathWithFlags, null);
  }

  /**
   * Creates an {@link AppleSource} given a (group name, [source1, source2, ...]) pair.
   */
  public static AppleSource ofSourceGroup(Pair<String, ImmutableList<AppleSource>> sourceGroup) {
    return new AppleSource(Type.SOURCE_GROUP, null, null, sourceGroup);
  }

  @Override
  public boolean equals(Object other) {
    if (other instanceof AppleSource) {
      AppleSource that = (AppleSource)other;
      return Objects.equals(this.type, that.type)
          && Objects.equals(this.sourcePath, that.sourcePath)
          && Objects.equals(this.sourcePathWithFlags, that.sourcePathWithFlags)
          && Objects.equals(this.sourceGroup, that.sourceGroup);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Objects.hash(type, sourcePath, sourcePathWithFlags, sourceGroup);
  }
}

@@ -2049,239 +2049,98 @@
     
-Preconditions.checkState(%0A        sourcePath != null %7C%7C sourcePathWithFlags != null %7C%7C sourceGroup != null,%0A        %22At least one of sourcePath, sourcePathWithFlags, or sourceGroup must be non-null%22);%0A    if (sourcePath != null) %7B%0A
+switch (type) %7B%0A      case SOURCE_PATH:%0A        Preconditions.checkNotNull(sourcePath);%0A  
     
@@ -2160,33 +2160,25 @@
 ns.check
-State(%0A          
+Argument(
 sourcePa
@@ -2200,95 +2200,47 @@
 null
- && sourceGroup == null,%0A          %22If sourcePath is non-null, sourcePathWithFlags and 
+);%0A        Preconditions.checkArgument(
 sour
@@ -2251,69 +2251,70 @@
 oup 
-must be
+==
  null
-%22
 );%0A    
+   
-%7D%0A    if (sourcePathWithFlags != null) %7B%0A
+ break;%0A      case SOURCE_PATH_WITH_FLAGS:%0A  
     
@@ -2334,33 +2334,25 @@
 ns.check
-State(%0A          
+Argument(
 sourcePa
@@ -2365,95 +2365,104 @@
 null
- && sourceGroup == null,%0A          %22If sourcePathWithFlags is non-null, sourcePath and 
+);%0A        Preconditions.checkNotNull(sourcePathWithFlags);%0A        Preconditions.checkArgument(
 sour
@@ -2473,61 +2473,60 @@
 oup 
-must be
+==
  null
-%22
 );%0A    
-%7D%0A    if (sourceGroup != null) %7B%0A
+    break;%0A      case SOURCE_GROUP:%0A  
     
@@ -2550,25 +2550,17 @@
 heck
-State(%0A          
+Argument(
 sour
@@ -2573,20 +2573,55 @@
  == null
- && 
+);%0A        Preconditions.checkArgument(
 sourcePa
@@ -2639,17 +2639,18 @@
  == null
-,
+);
 %0A       
@@ -2654,87 +2654,150 @@
     
-  %22If sourceGroup is non-null, sourcePath and sourcePathWithFlags must be null%22
+Preconditions.checkNotNull(sourceGroup);%0A        break;%0A      default:%0A        throw new IllegalArgumentException(%22Unrecognized type: %22 + type
 );%0A 
@@ -4012,21 +4012,20 @@
 .SOURCE_
-GROUP
+PATH
 , source

Fix typo in `AppleSource.ofSourcePath()`.