/*
 * Copyright (c) 2014-2015 University of Ulm
 *
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.  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 de.uniulm.omi.cloudiator.lance.lca.containers.docker;

import de.uniulm.omi.cloudiator.lance.container.spec.os.OperatingSystem;
import de.uniulm.omi.cloudiator.lance.lca.container.ComponentInstanceId;
import de.uniulm.omi.cloudiator.lance.lca.containers.docker.connector.DockerConnector;
import de.uniulm.omi.cloudiator.lance.lca.containers.docker.connector.DockerException;

final class DockerImageHandler {
    
    private final DockerOperatingSystemTranslator translator;
    private final OperatingSystem os;
    private final DockerConnector client;
    
    private volatile ImageCreationType initSource;
    
    DockerImageHandler(OperatingSystem osParam, DockerOperatingSystemTranslator translatorParam, DockerConnector clientParam) {
        if(osParam == null) throw new NullPointerException("operating system has to be set.");
        
        os = osParam;
        translator = translatorParam;
        client = clientParam;
    }

    private String buildImageTagName(ImageCreationType type, String componentInstallId) {
        final String key;
        if(type == ImageCreationType.COMPONENT) { 
            String tmpkey = componentInstallId; 
            String ostag = os.toString();
            ostag = ostag.replaceAll(":",  "_");
            key = tmpkey.toLowerCase() + ":" + ostag.toLowerCase();
        }
        else if(type == ImageCreationType.OPERATING_SYSTEM) { key = translator.translate(os); }
        else if(type == ImageCreationType.COMPONENT_INSTANCE) { throw new UnsupportedOperationException(); }
        else { throw new IllegalArgumentException(); }
        
        return key;
    }
    
    private String doGetSingleImage(String key) throws DockerException {
        // TODO: remove this as soon as access to a private registry is set
        if(client.findImage(key) != null) return key;
                
        try { client.pullImage(key); return key; }
        catch(DockerException de) { return null; }
    }

    
    String doPullImages(ComponentInstanceId myId, String componentInstallId) throws DockerException {
        // first step: try to find matching image for configured component
        // currently not implemented; TODO: implement
        
        // second step: try to find matching image for prepared component
        String target = buildImageTagName(ImageCreationType.COMPONENT, componentInstallId);
        String result = doGetSingleImage(target);
        if(result != null) {
            initSource = ImageCreationType.COMPONENT;
            return result; //FIXME: set in component lifecycle stage
        }
        
        // third step
        target = buildImageTagName(ImageCreationType.OPERATING_SYSTEM, null);
        result = doGetSingleImage(target);
        if(result == null) {
            throw new DockerException("cannot pull image: " + myId + " for key " + target);
        }
        initSource = ImageCreationType.OPERATING_SYSTEM;
        return target;
    }

    /** here, we may want to run a snapshotting action 
     * @throws DockerException */
    void runPostInstallAction(ComponentInstanceId myId, String componentInstallId) throws DockerException {
        if(initSource == ImageCreationType.OPERATING_SYSTEM) {
            // we probably will not need this return value
            // let's keep it for debugging purposes, though
            // @SuppressWarnings("unused") String imageSnapshot = 
            client.createImageSnapshot(myId, componentInstallId, os);
        }
    }
    
    static enum ImageCreationType {
        COMPONENT,
        COMPONENT_INSTANCE,
        OPERATING_SYSTEM,
    }

    OperatingSystem getOperatingSystem() { return os; }
}

@@ -1799,37 +1799,35 @@
     
-if(type == ImageCreationType.
+switch(type)%7B%0A        case 
 COMP
@@ -1831,19 +1831,17 @@
 OMPONENT
-) %7B
+:
  %0A      
@@ -1846,260 +1846,84 @@
     
-    String tmpkey = componentInstallId; %0A            String ostag = os.toString();%0A            ostag = ostag.replaceAll(%22:%22,  %22_%22);%0A            key = tmpkey.toLowerCase() + %22:%22 + ostag.toLowerCase();%0A        %7D%0A        else if(type == ImageCreationType.
+%09key = imageFromComponent(componentInstallId);%0A        %09break;%0A        case 
 OPER
@@ -1934,20 +1934,27 @@
 G_SYSTEM
-) %7B 
+:%0A        %09
 key = tr
@@ -1976,18 +1976,16 @@
 ate(os);
- %7D
 %0A       
@@ -1989,42 +1989,29 @@
     
-else if(type == ImageCreationType.
+%09break;%0A        case 
 COMP
@@ -2024,20 +2024,27 @@
 INSTANCE
-) %7B 
+:%0A        %09
 throw ne
@@ -2069,34 +2069,32 @@
 tionException();
- %7D
 %0A        else %7B 
@@ -2090,15 +2090,26 @@
     
-else %7B 
+default:%0A        %09
 thro
@@ -2145,38 +2145,312 @@
 n();
- %7D%0A        %0A        return key
+%0A        %7D        %0A        return key;%0A    %7D%0A    %0A    private String imageFromComponent(String componentInstallId)%7B%0A    %09String tmpkey = componentInstallId; %0A        String ostag = os.toString();%0A        ostag = ostag.replaceAll(%22:%22,  %22_%22);%0A        return tmpkey.toLowerCase() + %22:%22 + ostag.toLowerCase()
 ;%0A  

restructure code to build image tage name