/*
 * Copyright (C) 2017 Original Authors
 *
 * 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 org.csanchez.jenkins.plugins.kubernetes.pipeline;

import hudson.model.TaskListener;
import hudson.util.LogTaskListener;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.ContainerResource;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
import io.fabric8.kubernetes.client.dsl.LogWatch;
import io.fabric8.kubernetes.client.dsl.PrettyLoggable;
import io.fabric8.kubernetes.client.dsl.TailPrettyLoggable;
import io.fabric8.kubernetes.client.dsl.TimeTailPrettyLoggable;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ContainerLogStepExecution extends SynchronousNonBlockingStepExecution<String> {
    private static final long serialVersionUID = 5588861066775717487L;
    private static final transient Logger LOGGER = Logger.getLogger(ContainerLogStepExecution.class.getName());

    private final ContainerLogStep step;
    private transient KubernetesClient client;

    ContainerLogStepExecution(ContainerLogStep step, StepContext context) {
        super(context);
        this.step = step;
    }

    private PrintStream logger() {
        TaskListener l = null;
        StepContext context = getContext();
        try {
            l = context.get(TaskListener.class);
        } catch (Exception x) {
            LOGGER.log(Level.WARNING, "Failed to find TaskListener in context");
        } finally {
            if (l == null) {
                l = new LogTaskListener(LOGGER, Level.FINE);
            }
        }
        return l.getLogger();
    }

    @Override
    protected String run() throws Exception {
        boolean returnLog = step.isReturnLog();
        String containerName = step.getName();
        int tailingLines = step.getTailingLines();
        int sinceSeconds = step.getSinceSeconds();
        int limitBytes = step.getLimitBytes();

        try {
            LOGGER.log(Level.FINE, "Starting containerLog step.");

            KubernetesNodeContext nodeContext = new KubernetesNodeContext(getContext());
            client = nodeContext.connectToCloud();

            String podName = nodeContext.getPodName();
            ContainerResource<String, LogWatch, InputStream, PipedOutputStream, OutputStream, PipedInputStream,
                    String, ExecWatch, Boolean, InputStream> container = client.pods() //
                    .inNamespace(nodeContext.getNamespace()) //
                    .withName(podName) //
                    .inContainer(containerName);

            TimeTailPrettyLoggable<String, LogWatch> limited = limitBytes > 0 ? container.limitBytes(limitBytes) : container;

            TailPrettyLoggable<String, LogWatch> since = sinceSeconds > 0 ? limited.sinceSeconds(sinceSeconds) : limited;

            PrettyLoggable<String, LogWatch> tailed = tailingLines > 0 ? since.tailingLines(tailingLines) : since;
            String log = tailed.getLog();

            if (returnLog) {
                return log;
            } else {
                logger().println("> start log of container '" + containerName + "' in pod '" + podName + "'");
                logger().print(log);
                if (log.length() > 0 && log.charAt(log.length() - 1) != '\n') {
                    logger().println();
                }
                logger().println("> end log of container '" + containerName + "' in pod '" + podName + "'");
            }

            return "";
        } catch (InterruptedException e) {
            logger().println("Interrupted while getting logs of container");
            LOGGER.log(Level.FINE, "interrupted while getting logs of container {1}", containerName);
            return "";
        } catch (Exception e) {
            String message = "Failed to get logs for container";
            logger().println(message);
            LOGGER.log(Level.WARNING, message, e);
            return "";
        }
    }

    @Override
    public void stop(Throwable cause) throws Exception {
        LOGGER.log(Level.FINE, "Stopping container log step.");
        super.stop(cause);
    }
}

@@ -764,31 +764,73 @@
 tes.
-client.KubernetesClient
+api.model.DoneablePod;%0Aimport io.fabric8.kubernetes.api.model.Pod
 ;%0Aim
@@ -867,29 +867,24 @@
 ent.
-dsl.ContainerResource
+KubernetesClient
 ;%0Aim
@@ -921,20 +921,19 @@
 ent.dsl.
-Exec
+Log
 Watch;%0Ai
@@ -967,32 +967,35 @@
 .client.dsl.
-LogWatch
+PodResource
 ;%0Aimport io.
@@ -1307,132 +1307,8 @@
 n;%0A%0A
-import java.io.InputStream;%0Aimport java.io.OutputStream;%0Aimport java.io.PipedInputStream;%0Aimport java.io.PipedOutputStream;%0A
 impo
@@ -2952,178 +2952,41 @@
     
-ContainerResource%3CString, LogWatch, InputStream, PipedOutputStream, OutputStream, PipedInputStream,%0A                    String, ExecWatch, Boolean, InputStream%3E container
+PodResource%3CPod, DoneablePod%3E pod
  = c
@@ -3107,59 +3107,8 @@
 ame)
- //%0A                    .inContainer(containerName)
 ;%0A%0A 
@@ -3183,19 +3183,55 @@
 ytes %3E 0
- ? 
+%0A                    ? pod.inContainer(
 containe
@@ -3231,16 +3231,21 @@
 ontainer
+Name)
 .limitBy
@@ -3259,19 +3259,55 @@
 itBytes)
- : 
+%0A                    : pod.inContainer(
 containe
@@ -3307,16 +3307,21 @@
 ontainer
+Name)
 ;%0A%0A     

Fix compilation, avoids importing that crazy generic generated type