package de.japkit.examples.freebuilder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import de.japkit.annotations.RuntimeMetadata;
import de.japkit.metaannotations.Case;
import de.japkit.metaannotations.Clazz;
import de.japkit.metaannotations.CodeFragment;
import de.japkit.metaannotations.Constructor;
import de.japkit.metaannotations.Field;
import de.japkit.metaannotations.Getter;
import de.japkit.metaannotations.InnerClass;
import de.japkit.metaannotations.Matcher;
import de.japkit.metaannotations.Method;
import de.japkit.metaannotations.Setter;
import de.japkit.metaannotations.Var;
import de.japkit.metaannotations.classselectors.GeneratedClass;
import de.japkit.metaannotations.classselectors.SrcType;

@RuntimeMetadata
@Clazz(nameSuffixToAppend = "Builder")
public class FreeBuilderTemplate {

	@Var(fun = SrcType.class)
	interface Interfaze {
	};

	@Var(fun = GeneratedClass.class)
	class Builder {
	};

	@Field(src = "#{properties}",
			srcVar = "p",
			getter = @Getter(commentExpr = "the value that will be returned by {@link #{interfaze.simpleName}##{p.getter.simpleName}()}."),
			setter = @Setter(chain = true,
					commentExpr = "the value to be returned by {@link #{interfaze.simpleName}##{p.getter.simpleName}()}."))
	private SrcType $name$;

	@InnerClass
	static final class Value implements Interfaze {
		@Field(src = "#{properties}",
				srcVar = "p",
				getter = @Getter())
		private final SrcType $name$ = null;

		@Matcher(type = Date.class)
		public class isDate{}
		
		@Matcher(type = List.class)
		public class isList{}
		
		@Matcher(type = Set.class)
		public class isSet{}
		
		@CodeFragment(imports = {Date.class, ArrayList.class, HashSet.class, Collections.class},
				cases = { @Case(condFun=isDate.class, value = "new Date(#{surrounded}.getTime())"),
						@Case(condFun=isList.class, value = "Collections.unmodifiableList(new ArrayList<>(#{surrounded}))"),
						@Case(condFun=isSet.class, value = "Collections.unmodifiableSet(new HashSet<>(#{surrounded}))") })
		static class defensiveCopyFragment {
		}
		
		@CodeFragment(code = "builder.#{name}", surroundingFragments = "defensiveCopyFragment")
		static class rhs{}
		
		@CodeFragment(code = "this.#{name} = #{rhs()};")
		static class assignment {
		}

		@Constructor(bodyIterator = "#{properties}",
				bodyCode = "#{assignment()}")
		private Value(Builder builder) {

		}

		/**
		 * @japkit.bodyBeforeIteratorCode
		 * 
		 * <pre>
		 * if (!(obj instanceof Value)) {
		 * 	return false;
		 * }
		 * Value other = (Value) obj;
		 * return
		 * </pre>
		 * 
		 * @japkit.bodyCode Objects.equals(#{name}, other.#{name})
		 * @japkit.bodyAfterIteratorCode ;
		 */
		@Method(imports = Objects.class,
				bodyIterator = "#{properties}",
				bodySeparator = " && ",
				bodyIndentAfterLinebreak = true)
		@Override
		public boolean equals(Object obj) {
			return true;
		}

		@Method(imports = Objects.class,
				bodyBeforeIteratorCode = "return Objects.hash(",
				bodyIterator = "#{properties}",
				bodyCode = "#{name}",
				bodySeparator = ", ",
				bodyLinebreak = false,
				bodyAfterIteratorCode = ");")
		@Override
		public int hashCode() {
			return 0;
		}

		/**
		 * @japkit.bodyBeforeIteratorCode return "#{interfaze.simpleName} {"+
		 * @japkit.bodyCode "#{name}=" + #{name} +
		 * @japkit.bodySeparator ", " +
		 * @japkit.bodyAfterIteratorCode "}";
		 */
		@Method(bodyIterator = "#{properties}",
				bodyIndentAfterLinebreak = true)
		@Override
		public String toString() {
			return "";
		}
	}

}

@@ -677,24 +677,65 @@
 ons.Setter;%0A
+import de.japkit.metaannotations.Switch;%0A
 import de.ja
@@ -1648,21 +1648,26 @@
 %09public 
-class
+@interface
  isDate%7B
@@ -1710,21 +1710,26 @@
 %09public 
-class
+@interface
  isList%7B
@@ -1771,21 +1771,26 @@
 %09public 
-class
+@interface
  isSet%7B%7D
@@ -1799,127 +1799,116 @@
 %09%0A%09%09
-@CodeFragment(imports = %7BDate.class, ArrayList.class, HashSet.class, Collections
+%0A%09%09@Switch%0A%09%09static class defensiveCopyFragment %7B%0A%09%09%09@Case(condFun=isDate
 .class
-%7D,
+)
 %0A%09%09%09
-%09cases = %7B @Case(condFun=is
+@CodeFragment(imports = 
 Date
@@ -1911,28 +1911,27 @@
 Date.class, 
-valu
+cod
 e = %22new Dat
@@ -1954,29 +1954,49 @@
 getTime())%22)
-,
+%0A%09%09%09String copyDate;
 %0A%09%09%09
+%0A
 %09%09%09@Case(con
@@ -2008,30 +2008,94 @@
 isList.class
-, valu
+)%0A%09%09%09@CodeFragment(imports = %7BArrayList.class, Collections.class%7D, cod
 e = %22Collect
@@ -2149,21 +2149,41 @@
 ded%7D))%22)
-,
 %0A%09%09%09
+String copyList;%0A%09%09%09%0A
 %09%09%09@Case
@@ -2206,14 +2206,76 @@
 lass
-, valu
+)%0A%09%09%09@CodeFragment(imports = %7BHashSet.class, Collections.class%7D, cod
 e = 
@@ -2338,50 +2338,27 @@
 ))%22)
- %7D)%0A%09%09static class defensiveCopyFragment %7B
+%0A%09%09%09String copySet;
 %0A%09%09%7D
@@ -2471,24 +2471,26 @@
 ss rhs%7B%7D%0A%09%09%0A
+%09%0A
 %09%09@CodeFragm

Switch can be used with code fragments