package rollback

import (
	"fmt"

	kapi "k8s.io/kubernetes/pkg/api"

	deployapi "github.com/openshift/origin/pkg/deploy/api"
)

// RollbackGenerator generates a new DeploymentConfig by merging a pair of DeploymentConfigs
// in a configurable way.
type RollbackGenerator struct{}

// GenerateRollback creates a new DeploymentConfig by merging to onto from
// based on the options provided by spec. The LatestVersion of the result is
// unconditionally incremented, as rollback candidates are should be possible
// to be deployed manually regardless of other system behavior such as
// triggering.
//
// Any image change triggers on the new config are disabled to prevent
// triggered deployments from immediately replacing the rollback.
func (g *RollbackGenerator) GenerateRollback(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) {
	rollback := &deployapi.DeploymentConfig{}

	if err := kapi.Scheme.Convert(&from, &rollback); err != nil {
		return nil, fmt.Errorf("couldn't clone 'from' DeploymentConfig: %v", err)
	}

	// construct the candidate deploymentConfig based on the rollback spec
	if spec.IncludeTemplate {
		if err := kapi.Scheme.Convert(&to.Spec.Template, &rollback.Spec.Template); err != nil {
			return nil, fmt.Errorf("couldn't copy template to rollback:: %v", err)
		}
	}

	if spec.IncludeReplicationMeta {
		rollback.Spec.Replicas = to.Spec.Replicas
		rollback.Spec.Selector = map[string]string{}
		for k, v := range to.Spec.Selector {
			rollback.Spec.Selector[k] = v
		}
	}

	if spec.IncludeTriggers {
		if err := kapi.Scheme.Convert(&to.Spec.Triggers, &rollback.Spec.Triggers); err != nil {
			return nil, fmt.Errorf("couldn't copy triggers to rollback:: %v", err)
		}
	}

	if spec.IncludeStrategy {
		if err := kapi.Scheme.Convert(&to.Spec.Strategy, &rollback.Spec.Strategy); err != nil {
			return nil, fmt.Errorf("couldn't copy strategy to rollback:: %v", err)
		}
	}

	// Disable any image change triggers.
	for _, trigger := range rollback.Spec.Triggers {
		if trigger.Type == deployapi.DeploymentTriggerOnImageChange {
			trigger.ImageChangeParams.Automatic = false
		}
	}

	// TODO: add a new cause?
	rollback.Status.LatestVersion++

	return rollback, nil
}
