package com.mjrichardson.teamCity.buildTriggers;

import com.intellij.openapi.diagnostic.Logger;
import jetbrains.buildServer.ServiceLocator;
import jetbrains.buildServer.buildTriggers.BuildTriggerException;
import jetbrains.buildServer.buildTriggers.PolledTriggerContext;
import jetbrains.buildServer.buildTriggers.async.CheckJobStatusStorage;
import jetbrains.buildServer.buildTriggers.async.CheckResult;
import jetbrains.buildServer.buildTriggers.async.DetectionException;
import jetbrains.buildServer.buildTriggers.async.impl.AsyncPolledBuildTrigger;
import jetbrains.buildServer.serverSide.*;
import jetbrains.buildServer.users.SUser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutorService;

public class CustomAsyncPolledBuildTrigger<TItem> extends AsyncPolledBuildTrigger<TItem> {
    final Logger log;
    final CustomAsyncBuildTrigger<TItem> asyncBuildTrigger;
    final ServiceLocator serviceLocator;

    public CustomAsyncPolledBuildTrigger(ExecutorService executorService,
                                         Logger log,
                                         CheckJobStatusStorage<TItem> storage,
                                         int pollInterval,
                                         CustomAsyncBuildTrigger<TItem> asyncBuildTrigger,
                                         ServiceLocator serviceLocator) {
        super(executorService, log, storage, pollInterval, asyncBuildTrigger);
        this.log = log;
        this.asyncBuildTrigger = asyncBuildTrigger;
        this.serviceLocator = serviceLocator;
    }

    @Override
    public void triggerBuild(@NotNull PolledTriggerContext context) throws BuildTriggerException {
        CheckResult result = checkJobStatus(context.getBuildType(), context.getTriggerDescriptor(), context.getCustomDataStorage());
        if (result != null) {
            JobResult jobResult = mapCheckResultToJobResult(result);

            if (jobResult.shouldTriggerBuild()) {
                SBuildType buildType = serviceLocator.getSingletonService(ProjectManager.class)
                        .findBuildTypeByExternalId(context.getBuildType().getExternalId());
                SUser user = null;
                final BuildCustomizer customizer = serviceLocator.getSingletonService(BuildCustomizerFactory.class)
                        .createBuildCustomizer(buildType, user);
                customizer.setParameters(jobResult.properties);
                try {
                    log.debug("Creating build promotion");
                    BuildPromotionEx promotion = (BuildPromotionEx)customizer.createPromotion();
                    log.debug("Build promotion " + promotion.getId() + " created");

                    log.debug("Adding '" + buildType.toString() + "' to queue");
                    SQueuedBuild addResult = ((BuildTypeEx)buildType).addToQueue(promotion, jobResult.triggeredBy);
                    log.info("Added '" + addResult.toString() + "' to queue");
                }
                catch(Exception e) {
                    log.error("Failed to create the build promotion", e);
                }
            }

            if(jobResult.ex != null) {
                throw jobResult.ex;
            }
        }
    }

    @NotNull
    private JobResult mapCheckResultToJobResult(@NotNull CheckResult<TItem> checkResult) {
        JobResult summary = new JobResult();
        Throwable generalError = checkResult.getGeneralError();
        if(generalError != null) {
            summary.ex = asyncBuildTrigger.makeTriggerException(generalError);
        } else {
            Collection<DetectionException> errors = checkResult.getCheckErrors().values();
            if(!errors.isEmpty()) {
                DetectionException cause = errors.iterator().next();
                summary.ex = asyncBuildTrigger.makeTriggerException(cause);
            }
        }

        Collection<TItem> updated = checkResult.getUpdated();
        if (!updated.isEmpty()) {
            this.log.debug("changes detected in " + updated);
            TItem update = updated.iterator().next();
            summary.triggeredBy = asyncBuildTrigger.getRequestorString(update);
            summary.properties = asyncBuildTrigger.getProperties(update);
        } else {
            this.log.debug("changes not detected");
        }

        return summary;
    }

    private class JobResult {
        @Nullable
        private String triggeredBy;
        @Nullable
        private BuildTriggerException ex;
        @NotNull
        private Map<String, String> properties;

        public boolean shouldTriggerBuild() {
            return triggeredBy != null;
        }
    }
}

@@ -4285,24 +4285,36 @@
         
-summary.
+Map%3CString, String%3E 
 properti
@@ -4351,32 +4351,266 @@
 erties(update);%0A
+            for (Map.Entry%3CString, String%3E entry : properties.entrySet()) %7B%0A                this.log.debug(%22property%5B'%22 + entry.getKey() + %22'%5D = '%22 + entry.getValue() + %22'%22);%0A            %7D%0A            summary.properties = properties;%0A
         %7D else %7B

Add debug logging when setting properties on build