/*
 * Copyright 2013 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
 * 
 * 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 com.google.web.bindery.event.gwt.rebind.binder;

import static com.google.gwt.dev.util.Preconditions.checkArgument;

import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.google.web.bindery.event.shared.binder.EventBinder;
import com.google.web.bindery.event.shared.binder.GenericEvent;
import com.google.web.bindery.event.shared.binder.impl.AbstractEventBinder;
import com.google.web.bindery.event.shared.binder.impl.GenericEventHandler;

import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;

/**
 * Generator for {@link EventBinder}. Takes care of the ugly parts of creating 
 * the source writer and then delegates to {@link EventBinderWriter}. This class
 * is used by the GWT compiler and should not be referenced directly by users.
 *
 * @author ekuefler@google.com (Erik Kuefler)
 */
public class EventBinderGenerator extends Generator {

  @Override
  public String generate(TreeLogger logger, GeneratorContext context,
      String typeName) throws UnableToCompleteException {
    try {
      JClassType eventBinderType = context.getTypeOracle().getType(typeName);
      JClassType targetType = getTargetType(eventBinderType, context.getTypeOracle());
      SourceWriter writer = createSourceWriter(logger, context, eventBinderType, targetType);
      if (writer != null) { // Otherwise the class was already created
        new EventBinderWriter(
            logger,
            context.getTypeOracle().getType(GenericEvent.class.getCanonicalName()))
                .writeDoBindEventHandlers(targetType, writer);
        writer.commit(logger);
      }
      return getFullyQualifiedGeneratedClassName(eventBinderType);
    } catch (NotFoundException e) {
      logger.log(Type.ERROR, "Error generating " + typeName, e);
      throw new UnableToCompleteException();
    }
  }

  private JClassType getTargetType(JClassType interfaceType, TypeOracle typeOracle) {
    JClassType[] superTypes = interfaceType.getImplementedInterfaces();
    checkArgument(
        superTypes.length == 1
        && superTypes[0].isAssignableFrom(typeOracle.findType(EventBinder.class.getCanonicalName()))
        && superTypes[0].isParameterized() != null,
        interfaceType + " must extend EventBinder with a type parameter");
    return superTypes[0].isParameterized().getTypeArgs()[0];
  }

  private SourceWriter createSourceWriter(
      TreeLogger logger,
      GeneratorContext context,
      JClassType eventBinderType,
      JClassType targetType) {
    String simpleName = getSimpleGeneratedClassName(eventBinderType);
    String packageName = eventBinderType.getPackage().getName();
    ClassSourceFileComposerFactory composer =
        new ClassSourceFileComposerFactory(packageName, simpleName);

    composer.setSuperclass(AbstractEventBinder.class.getCanonicalName()
        + "<" + targetType.getName() + ">");
    composer.addImplementedInterface(eventBinderType.getName());

    composer.addImport(EventBinder.class.getCanonicalName());
    composer.addImport(EventBus.class.getCanonicalName());
    composer.addImport(GenericEvent.class.getCanonicalName());
    composer.addImport(GenericEventHandler.class.getCanonicalName());
    composer.addImport(HandlerRegistration.class.getCanonicalName());
    composer.addImport(LinkedList.class.getCanonicalName());
    composer.addImport(List.class.getCanonicalName());

    PrintWriter printWriter = context.tryCreate(logger, packageName, simpleName);
    return (printWriter != null) ? composer.createSourceWriter(context, printWriter) : null;
  }

  private String getSimpleGeneratedClassName(JClassType eventBinderType) {
    return eventBinderType.getName().replace('.', '_') + "Impl";
  }

  private String getFullyQualifiedGeneratedClassName(JClassType eventBinderType) {
    return new StringBuilder()
        .append(eventBinderType.getPackage().getName())
        .append('.')
        .append(getSimpleGeneratedClassName(eventBinderType))
        .toString();
  }
}

@@ -648,76 +648,8 @@
 r;%0A%0A
-import static com.google.gwt.dev.util.Preconditions.checkArgument;%0A%0A
 impo
@@ -3098,31 +3098,104 @@
     
-checkArgument(
+JClassType eventBinderType = typeOracle.findType(EventBinder.class.getCanonicalName());
 %0A    
-    
+if (
 supe
@@ -3208,17 +3208,17 @@
 .length 
-=
+!
 = 1%0A    
@@ -3213,35 +3213,36 @@
 th != 1%0A        
-&& 
+%7C%7C !
 superTypes%5B0%5D.is
@@ -3260,65 +3260,23 @@
 rom(
-typeOracle.findType(EventBinder.class.getCanonicalName())
+eventBinderType
 )%0A  
@@ -3285,10 +3285,10 @@
     
-&&
+%7C%7C
  sup
@@ -3320,17 +3320,63 @@
 d() 
-!
+=
 = null
-,%0A
+) %7B%0A      throw new IllegalArgumentException(%0A  
     
@@ -3442,24 +3442,30 @@
 arameter%22);%0A
+    %7D%0A
     return s

Remove dependency on the Preconditions class, which is being remove in GWT 2.6.