/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * 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 io.fabric8.kubernetes.client.dsl.internal;

import io.fabric8.kubernetes.api.builder.Visitor;
import io.fabric8.kubernetes.api.model.Doneable;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.ClientResource;

import java.lang.reflect.InvocationTargetException;

public class HasMetadataOperation<K extends KubernetesClient, T extends HasMetadata, L extends KubernetesResourceList, D extends Doneable<T>, R extends ClientResource<T, D>>
  extends BaseOperation<K, T, L, D, R> {

  protected HasMetadataOperation(K client, String resourceT, String namespace, String name, Boolean cascading, T item) {
    super(client, resourceT, namespace, name, cascading, item);
  }

  protected HasMetadataOperation(K client, String resourceT, String namespace, String name, Boolean cascading, T item, Class<K> clientType, Class<T> type, Class<L> listType, Class<D> doneableType) {
    super(client, resourceT, namespace, name, cascading, item, clientType, type, listType, doneableType);
  }

  @Override
  public D edit() throws KubernetesClientException {
    final BaseOperation oper = this;

    final Visitor<T> visitor = new Visitor<T>() {
      @Override
      public void visit(T resource) {
        try {
          if (isCascading() && !isReaping()) {
            Reaper reaper = ReaperFactory.getReaper(oper);
            if (reaper != null) {
              setReaping(true);
              reaper.reap();
            }
          }
          replace(resource);
        } catch (Exception e) {
          throw KubernetesClientException.launderThrowable(e);
        }
      }
    };

    try {
      return (D) getDoneableType().getDeclaredConstructor(getType(), Visitor.class).newInstance(get(), visitor);
    } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException | InstantiationException e) {
      throw KubernetesClientException.launderThrowable(e);
    }
  }

  @Override
  public T replace(T item) {
    try {
      if (isCascading()) {
        Reaper reaper = ReaperFactory.getReaper(this);
        if (reaper != null && !isReaping()) {
          setReaping(true);
          reaper.reap();
        }
      }
      item.getMetadata().setResourceVersion(null);
      return handleReplace(getResourceUrl(), item);
    } catch (Exception e) {
      throw KubernetesClientException.launderThrowable(e);
    }
  }
}

@@ -1038,16 +1038,73 @@
 esource;
+%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;
 %0A%0Aimport
@@ -1148,16 +1148,54 @@
 ception;
+%0Aimport java.util.concurrent.TimeUnit;
 %0A%0Apublic
@@ -1362,16 +1362,16 @@
 %3CT, D%3E%3E%0A
-
   extend
@@ -1404,16 +1404,109 @@
 , R%3E %7B%0A%0A
+  private static final Logger logger = LoggerFactory.getLogger(HasMetadataOperation.class);%0A%0A
   protec
@@ -2943,24 +2943,118 @@
 e(T item) %7B%0A
+    Exception caught = null;%0A    int maxTries = 5;%0A    for (int i = 0; i %3C maxTries; i++) %7B%0A  
     try %7B%0A  
@@ -3047,24 +3047,26 @@
       try %7B%0A
+  
       if (is
@@ -3080,32 +3080,34 @@
 ng()) %7B%0A        
+  
 Reaper reaper = 
@@ -3137,32 +3137,34 @@
 (this);%0A        
+  
 if (reaper != nu
@@ -3177,32 +3177,34 @@
 !isReaping()) %7B%0A
+  
           setRea
@@ -3217,32 +3217,34 @@
 rue);%0A          
+  
 reaper.reap();%0A 
@@ -3242,34 +3242,38 @@
 reap();%0A        
-%7D%0A
+  %7D%0A  
       %7D%0A      it
@@ -3270,16 +3270,18 @@
 %7D%0A      
+  
 item.get
@@ -3317,16 +3317,18 @@
 (null);%0A
+  
       re
@@ -3371,16 +3371,18 @@
  item);%0A
+  
     %7D ca
@@ -3395,32 +3395,286 @@
 xception e) %7B%0A  
+      caught = e;%0A        if (i %3C maxTries - 1) %7B%0A          try %7B%0A            TimeUnit.SECONDS.sleep(1);%0A          %7D catch (InterruptedException e1) %7B%0A            // Ignore this... would only hide the proper exception%0A          %7D%0A        %7D%0A      %7D%0A    %7D%0A
     throw Kubern
@@ -3706,28 +3706,27 @@
 erThrowable(
-e);%0A    %7D
+caught);
 %0A  %7D%0A%7D%0A

Add retry to replace method