/*
 * Copyright 2017 Google 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
 *
 *    https://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.dataportabilityproject;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import org.dataportabilityproject.dataModels.ContinuationInformation;
import org.dataportabilityproject.dataModels.DataModel;
import org.dataportabilityproject.dataModels.ExportInformation;
import org.dataportabilityproject.dataModels.Exporter;
import org.dataportabilityproject.dataModels.Importer;
import org.dataportabilityproject.dataModels.Resource;
import org.dataportabilityproject.shared.PortableDataType;
import org.dataportabilityproject.shared.auth.AuthData;

public class PortabilityCopier {
  // TODO: Use better monitoring, this is a hack!
  private static final AtomicInteger COPY_ITERATION_COUNTER = new AtomicInteger();

  // Start the copy data process
  public static <T extends DataModel> void copyDataType(ServiceProviderRegistry registry,
      PortableDataType dataType,
      String exportService,
      AuthData exportAuthData,
      String importService,
      AuthData importAuthData,
      String jobId) throws IOException {

    Exporter<T> exporter = registry.getExporter(exportService, dataType, jobId, exportAuthData);
    Importer<T> importer = registry.getImporter(importService, dataType, jobId, importAuthData);
    ExportInformation emptyExportInfo =
        new ExportInformation(Optional.empty(), Optional.empty());
    log("Starting copy job, id: %s, source: %s, destination: %s",
        jobId, exportService, importService);
    copy(exporter, importer, emptyExportInfo);
  }

  private static <T extends DataModel> void copy(
      Exporter<T> exporter,
      Importer<T> importer,
      ExportInformation exportInformation) throws IOException {
    log("copy iteration: %d", COPY_ITERATION_COUNTER.incrementAndGet());

    // NOTE: order is important bellow, do the import of all the items, then do continuation
    // then do sub resources, this ensures all parents are populated before children get
    // processed.

    log("Starting export, exportInformation: %s", exportInformation);
    T items = exporter.export(exportInformation);
    log("Finished export, results: %s", items);

    log("Starting import");
    // The collection of items can be both containers and items
    importer.importItem(items);
    log("Finished import");

    ContinuationInformation continuationInfo = items.getContinuationInformation();
    if (null != continuationInfo) {

      // Process the next page of items for the resource
      if (null != continuationInfo.getPaginationInformation()) {
        log("start off a new copy iteration with pagination info");
        copy(exporter, importer,
            new ExportInformation(
                exportInformation.getResource(), // Resource with additional pages to fetch
                Optional.of(continuationInfo.getPaginationInformation())));
      }

      // Start processing sub-resources
      if (continuationInfo.getSubResources() != null && !continuationInfo.getSubResources().isEmpty()) {
        log("start off a new copy iterations with a sub resource, size: %d",
            continuationInfo.getSubResources().size());
        for (Resource resource : continuationInfo.getSubResources()) {
          copy(
              exporter,
              importer,
              new ExportInformation(Optional.of(resource), Optional.empty()));
        }
      }
    }
  }

  // TODO: Replace with logging framework
  private static void log (String fmt, Object... args) {
    System.out.println(String.format("PortabilityCopier: " + fmt, args));
  }
}

@@ -1199,16 +1199,73 @@
 uthData;
+%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;
 %0A%0Apublic
@@ -1423,16 +1423,105 @@
 teger();
+%0A  private static final Logger logger = LoggerFactory.getLogger(PortabilityCopier.class);
 %0A%0A  // S
@@ -2130,32 +2130,41 @@
 mpty());%0A    log
+ger.debug
 (%22Starting copy 
@@ -2172,18 +2172,18 @@
 ob, id: 
-%25s
+%7B%7D
 , source
@@ -2184,18 +2184,18 @@
 source: 
-%25s
+%7B%7D
 , destin
@@ -2201,18 +2201,18 @@
 nation: 
-%25s
+%7B%7D
 %22,%0A     
@@ -2481,16 +2481,25 @@
 %0A    log
+ger.debug
 (%22copy i
@@ -2508,18 +2508,18 @@
 ration: 
-%25d
+%7B%7D
 %22, COPY_
@@ -2757,32 +2757,41 @@
 cessed.%0A%0A    log
+ger.debug
 (%22Starting expor
@@ -2812,18 +2812,18 @@
 mation: 
-%25s
+%7B%7D
 %22, expor
@@ -2886,32 +2886,41 @@
 mation);%0A    log
+ger.debug
 (%22Finished expor
@@ -2935,10 +2935,10 @@
 ts: 
-%25s
+%7B%7D
 %22, i
@@ -2952,16 +2952,25 @@
 %0A    log
+ger.debug
 (%22Starti
@@ -3085,16 +3085,25 @@
 %0A    log
+ger.debug
 (%22Finish
@@ -3361,32 +3361,41 @@
 )) %7B%0A        log
+ger.debug
 (%22start off a ne
@@ -3836,16 +3836,25 @@
      log
+ger.debug
 (%22start 
@@ -3910,10 +3910,10 @@
 ze: 
-%25d
+%7B%7D
 %22,%0A 
@@ -4212,185 +4212,7 @@
 %0A  %7D
-%0A%0A  // TODO: Replace with logging framework%0A  private static void log (String fmt, Object... args) %7B%0A    System.out.println(String.format(%22PortabilityCopier: %22 + fmt, args));%0A  %7D
 %0A%7D%0A

Switch PortabilityCopier to use Logger class instead of System.out