

package com.netflix.spinnaker.clouddriver.ecs.deploy.validators;

import com.amazonaws.services.ecs.model.PlacementStrategy;
import com.amazonaws.services.ecs.model.PlacementStrategyType;
import com.google.common.collect.Sets;
import com.netflix.spinnaker.clouddriver.ecs.EcsOperation;
import com.netflix.spinnaker.clouddriver.ecs.deploy.description.CreateServerGroupDescription;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperations;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

import java.util.List;
import java.util.Set;

@EcsOperation(AtomicOperations.CREATE_SERVER_GROUP)
@Component("ecsCreateServerGroupDescriptionValidator")
public class EcsCreateServerGroupDescriptionValidator extends CommonValidator {

  private static final Set<String> BINPACK_VALUES = Sets.newHashSet("cpu", "memory");
  private static final Set<String> SPREAD_VALUES = Sets.newHashSet(
    "instanceId",
    "attribute:ecs.availability-zone",
    "attribute:ecs.instance-type",
    "attribute:ecs.os-type",
    "attribute:ecs.ami-id"
  );

  public EcsCreateServerGroupDescriptionValidator() {
    super("createServerGroupDescription");
  }

  @Override
  public void validate(List priorDescriptions, Object description, Errors errors) {
    CreateServerGroupDescription createServerGroupDescription = (CreateServerGroupDescription) description;

    validateCredentials(createServerGroupDescription, errors, "credentials");
    validateCapacity(errors, createServerGroupDescription.getCapacity());

    if (createServerGroupDescription.getAvailabilityZones() != null) {
      if (createServerGroupDescription.getAvailabilityZones().size() != 1) {
        rejectValue(errors, "availabilityZones", "must.have.only.one");
      }
    } else {
      rejectValue(errors, "availabilityZones", "not.nullable");
    }

    if (createServerGroupDescription.getPlacementStrategySequence() != null) {
      for (PlacementStrategy placementStrategy : createServerGroupDescription.getPlacementStrategySequence()) {
        PlacementStrategyType type;
        try {
          type = PlacementStrategyType.fromValue(placementStrategy.getType());
        } catch (IllegalArgumentException e) {
          rejectValue(errors, "placementStrategySequence.type", "invalid");
          continue;
        }

        switch (type) {
          case Random:
            break;
          case Spread:
            if (!SPREAD_VALUES.contains(placementStrategy.getField())) {
              rejectValue(errors, "placementStrategySequence.spread", "invalid");
            }
            break;
          case Binpack:
            if (!BINPACK_VALUES.contains(placementStrategy.getField())) {
              rejectValue(errors, "placementStrategySequence.binpack", "invalid");
            }
            break;
        }

      }
    } else {
      rejectValue(errors, "placementStrategySequence", "not.nullable");
    }

    if (createServerGroupDescription.getAutoscalingPolicies() == null) {
      rejectValue(errors, "autoscalingPolicies", "not.nullable");
    }

    if (createServerGroupDescription.getApplication() == null) {
      rejectValue(errors, "application", "not.nullable");
    }

    if (createServerGroupDescription.getEcsClusterName() == null) {
      rejectValue(errors, "ecsClusterName", "not.nullable");
    }

    if (createServerGroupDescription.getDockerImageAddress() == null) {
      rejectValue(errors, "dockerImageAddress", "not.nullable");
    }

    if (createServerGroupDescription.getContainerPort() != null) {
      if (createServerGroupDescription.getContainerPort() < 0 || createServerGroupDescription.getContainerPort() > 65535) {
        rejectValue(errors, "containerPort", "invalid");
      }
    } else {
      rejectValue(errors, "containerPort", "not.nullable");
    }

    if (createServerGroupDescription.getComputeUnits() != null) {
      if (createServerGroupDescription.getComputeUnits() < 0) {
        rejectValue(errors, "computeUnits", "invalid");
      }
    } else {
      rejectValue(errors, "computeUnits", "not.nullable");
    }

    if (createServerGroupDescription.getReservedMemory() != null) {
      if (createServerGroupDescription.getReservedMemory() < 0) {
        rejectValue(errors, "reservedMemory", "invalid");
      }
    } else {
      rejectValue(errors, "reservedMemory", "not.nullable");
    }

  }

}
