package io.vrap.rmf.raml.generic.generator.php;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.Resources;
import io.vrap.rmf.raml.model.types.AnyType;
import io.vrap.rmf.raml.model.types.BuiltinType;
import io.vrap.rmf.raml.model.types.ObjectType;
import io.vrap.rmf.raml.model.types.StringType;
import io.vrap.rmf.raml.model.types.util.TypesSwitch;
import org.apache.commons.lang3.StringUtils;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TypesGenerator {
    private final STGroup interfaceSTGroup;
    private final TypeGeneratingVisitor typeGeneratingVisitor;

    public TypesGenerator() throws IOException
    {
        final URL resource = Resources.getResource("./templates/php/interface.stg");
        interfaceSTGroup = new STGroupFile(resource, "UTF-8", '<', '>');
        interfaceSTGroup.load();
        interfaceSTGroup.registerRenderer(String.class,
                (arg, formatString, locale) ->
                        "capitalize".equals(formatString) ?
                                StringUtils.capitalize(arg.toString()) :
                                arg.toString());
        typeGeneratingVisitor = new TypeGeneratingVisitor("types");
    }

    public void generate(final List<AnyType> types, final File outputPath) throws IOException {
        for (final AnyType anyType : types) {
            final String generate = generateFile(anyType);
            if (generate != null) {
                final File sourceFile = new File(outputPath, anyType.getName().concat(".php"));
                if (!sourceFile.exists()) {
                    Files.createFile(sourceFile.toPath());
                }
                Files.write(sourceFile.toPath(), generate.getBytes(StandardCharsets.UTF_8));
            }
        }
    }

    @VisibleForTesting
    String generateFile(final AnyType type) {
        return typeGeneratingVisitor.doSwitch(type);
    }

    private class TypeGeneratingVisitor extends TypesSwitch<String> {
        private final String packageName;

        public TypeGeneratingVisitor(String packageName) {
            this.packageName = packageName;
        }

        @Override
        public String caseStringType(final StringType stringType) {
            if (stringType.getEnum().isEmpty()) {
                return null;
            }
            return null;
        }

        @Override
        public String caseObjectType(final ObjectType objectType) {
            if (objectType.getName() == null) {
                return null;
            } else {
                final ST interfaceST = interfaceSTGroup.getInstanceOf("interface");
                interfaceST.add("type", objectType);
                final List<String> builtInTypes = Arrays.stream(BuiltinType.values()).map(BuiltinType::getName).collect(Collectors.toList());;
                final Boolean builtInParentType = objectType.getType() == null || builtInTypes.contains(objectType.getType().getName());
                interfaceST.add("builtInParent", builtInParentType);
                interfaceST.add("package", packageName);
                return interfaceST.render();
            }
        }
    }
}

@@ -463,46 +463,8 @@
 ST;%0A
-import org.stringtemplate.v4.STGroup;%0A
 impo
@@ -779,55 +779,16 @@
 nal 
-STGroup interfaceSTGroup;%0A    private final Typ
+Interfac
 eGen
@@ -802,19 +802,24 @@
 Visitor 
-typ
+interfac
 eGenerat
@@ -990,447 +990,91 @@
 face
-STGroup = new STGroupFile(resource, %22UTF-8%22, '%3C', '%3E');%0A        interfaceSTGroup.load();%0A        interfaceSTGroup.registerR
+GeneratingVisitor = new InterfaceG
 en
-d
 er
-er(String.class,%0A                (arg, formatString, locale) -%3E%0A                        %22capitalize%22.equals(formatString) ?%0A                                StringUtils.capitalize(arg.toString()) :%0A                                arg.toString());%0A        typeGeneratingVisitor = new TypeGeneratingVisitor(%22types%22
+atingVisitor(%22types%22, createSTGroup(resource)
 );%0A 
@@ -1653,24 +1653,498 @@
    %7D%0A    %7D%0A%0A
+    private STGroupFile createSTGroup(final URL resource) %7B%0A        final STGroupFile stGroup = new STGroupFile(resource, %22UTF-8%22, '%3C', '%3E');%0A        stGroup.load();%0A        stGroup.registerRenderer(String.class,%0A                (arg, formatString, locale) -%3E%0A                        %22capitalize%22.equals(formatString) ?%0A                                StringUtils.capitalize(arg.toString()) :%0A                                arg.toString());%0A        return stGroup;%0A    %7D%0A%0A%0A
     @Visible
@@ -2215,19 +2215,24 @@
  return 
-typ
+interfac
 eGenerat
@@ -2283,19 +2283,24 @@
 e class 
-Typ
+Interfac
 eGenerat
@@ -2381,16 +2381,68 @@
 ageName;
+%0A        private final STGroupFile interfaceSTGroup;
 %0A%0A      
@@ -2450,19 +2450,24 @@
  public 
-Typ
+Interfac
 eGenerat
@@ -2477,16 +2477,22 @@
 Visitor(
+final 
 String p
@@ -2501,19 +2501,109 @@
 kageName
-) %7B
+, final STGroupFile interfaceSTGroup) %7B%0A            this.interfaceSTGroup = interfaceSTGroup;
 %0A       

refactor php type generator