/*
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.litho.sections.processor;

import com.facebook.litho.sections.annotations.DiffSectionSpec;
import com.facebook.litho.sections.annotations.GroupSectionSpec;
import com.facebook.litho.sections.processor.specmodels.model.DelegateMethodDescriptions;
import com.facebook.litho.sections.processor.specmodels.model.DiffSectionSpecModel;
import com.facebook.litho.sections.processor.specmodels.model.GroupSectionSpecModel;
import com.facebook.litho.sections.processor.specmodels.model.HasService;
import com.facebook.litho.specmodels.generator.BuilderGenerator;
import com.facebook.litho.specmodels.generator.ComponentImplGenerator;
import com.facebook.litho.specmodels.generator.DelegateMethodGenerator;
import com.facebook.litho.specmodels.generator.EventGenerator;
import com.facebook.litho.specmodels.generator.PreambleGenerator;
import com.facebook.litho.specmodels.generator.StateGenerator;
import com.facebook.litho.specmodels.generator.TreePropGenerator;
import com.facebook.litho.specmodels.model.DependencyInjectionHelper;
import com.facebook.litho.specmodels.model.SpecModel;
import javax.annotation.Nullable;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;

/**
 * Processor used to generate <code>com.facebook.litho.sections.SectionLifecycle</code> and
 * <code>com.facebook.litho.sections.Section</code> classes for a {@link GroupSectionSpec}
 * or a {@link DiffSectionSpec}.
 */
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class SectionsComponentProcessor extends AbstractSectionsComponentProcessor {

  @Override
  protected void generate(GroupSectionSpecHelper groupSectionSpecHelper) {
    final GroupSectionSpecModel specModel = groupSectionSpecHelper.getSpecModel();
    generateCommonListComponent(groupSectionSpecHelper);
    DelegateMethodGenerator.generateDelegates(
        specModel,
        DelegateMethodDescriptions.getGroupSectionSpecDelegatesMap(specModel))
        .addToTypeSpec(groupSectionSpecHelper.getTypeSpec());
    TreePropGenerator.generate(specModel).addToTypeSpec(groupSectionSpecHelper.getTypeSpec());
  }

  @Override
  protected void generate(DiffSectionSpecHelper diffSectionSpecHelper) {
    final DiffSectionSpecModel specModel = diffSectionSpecHelper.getSpecModel();
    generateCommonListComponent(diffSectionSpecHelper);
    DelegateMethodGenerator.generateDelegates(
            specModel, DelegateMethodDescriptions.getDiffSectionSpecDelegatesMap(specModel))
        .addToTypeSpec(diffSectionSpecHelper.getTypeSpec());
  }

  private <S extends SpecModel & HasService> void generateCommonListComponent(
      ListSpecHelper<S> listSpecHelper) {
    S specModel = listSpecHelper.getSpecModel();
    listSpecHelper.getTypeSpec().addModifiers(Modifier.FINAL);
    final Stages stages = listSpecHelper.getStages();

    stages.generateSourceDelegate(true);
    PreambleGenerator.generate(specModel).addToTypeSpec(listSpecHelper.getTypeSpec());

    ComponentImplGenerator.generate(specModel, specModel.getServiceParam())
        .addToTypeSpec(listSpecHelper.getTypeSpec());
    BuilderGenerator.generate(specModel).addToTypeSpec(listSpecHelper.getTypeSpec());
    StateGenerator.generate(specModel).addToTypeSpec(listSpecHelper.getTypeSpec());
    EventGenerator.generate(specModel).addToTypeSpec(listSpecHelper.getTypeSpec());
  }

  @Override
  @Nullable
  protected DependencyInjectionHelper getDependencyInjectionGenerator(TypeElement typeElement) {
    return null;
  }
}

@@ -1398,24 +1398,63 @@
 .SpecModel;%0A
+import com.squareup.javapoet.TypeSpec;%0A
 import javax
@@ -2222,16 +2222,25 @@
 mponent(
+%0A        
 groupSec
@@ -2245,32 +2245,85 @@
 ectionSpecHelper
+.getSpecModel(), groupSectionSpecHelper.getTypeSpec()
 );%0A    DelegateM
@@ -2774,32 +2774,108 @@
 getSpecModel();%0A
+    final TypeSpec.Builder typeSpec = diffSectionSpecHelper.getTypeSpec();%0A%0A
     generateComm
@@ -2890,37 +2890,35 @@
 mponent(
-diffSectionSpecHelper
+specModel, typeSpec
 );%0A    D
@@ -3207,48 +3207,102 @@
     
-ListSpecHelper%3CS%3E listSpecHelper
+S specModel, TypeSpec.Builder typeSpec) %7B%0A%0A    if (specModel.hasInjectedDependencies()
 ) %7B%0A    
 S sp
@@ -3293,25 +3293,25 @@
 es()) %7B%0A    
-S
+ 
  specModel =
@@ -3312,74 +3312,112 @@
 odel
- = listSpec
+.getDependencyInjection
 Helper
+()
 .ge
-tSpecModel();%0A    listSpecHelper.getT
+nerate(specModel).addToTypeSpec(typeSpec);%0A    %7D else %7B%0A      t
 ypeSpec
-()
 .add
@@ -3451,99 +3451,10 @@
     
-final Stages stages = listSpecHelper.getStages();%0A%0A    stages.generateSourceDelegate(true);
+%7D%0A
 %0A   
@@ -3510,40 +3510,19 @@
 pec(
-listSpecHelper.getT
+t
 ypeSpec
-()
 );%0A
-%0A
     
@@ -3592,25 +3592,16 @@
 Param())
-%0A        
 .addToTy
@@ -3611,36 +3611,16 @@
 pec(
-listSpecHelper.getT
+t
 ypeSpec
-()
 );%0A 
@@ -3677,36 +3677,16 @@
 pec(
-listSpecHelper.getT
+t
 ypeSpec
-()
 );%0A 
@@ -3741,36 +3741,16 @@
 pec(
-listSpecHelper.getT
+t
 ypeSpec
-()
 );%0A 
@@ -3805,36 +3805,16 @@
 pec(
-listSpecHelper.getT
+t
 ypeSpec
-()
 );%0A 

Remove Stages from processor