/*
 * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.yang.data.impl.codec;

import static java.util.Objects.requireNonNull;

import java.util.Optional;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Int8TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;

public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
    private final Class<J> inputClass;
    private final T typeDefinition;

    protected TypeDefinitionAwareCodec(final Optional<T> typeDefinition, final Class<J> outputClass) {
        this.typeDefinition = typeDefinition.orElse(null);
        this.inputClass = requireNonNull(outputClass);
    }

    @Override
    public Class<J> getInputClass() {
        return inputClass;
    }

    public Optional<T> getTypeDefinition() {
        return Optional.ofNullable(typeDefinition);
    }

    @SuppressWarnings("unchecked")
    public static TypeDefinitionAwareCodec<Object, ?> from(final TypeDefinition<?> typeDefinition) {
        return (TypeDefinitionAwareCodec<Object, ?>) fromType(typeDefinition);
    }

    public static TypeDefinitionAwareCodec<?, ?> fromType(final TypeDefinition<?> typeDefinition) {
        final TypeDefinitionAwareCodec<?, ?> codec;

        if (typeDefinition instanceof BinaryTypeDefinition) {
            codec = BinaryStringCodec.from((BinaryTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof BitsTypeDefinition) {
            codec = BitsStringCodec.from((BitsTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof BooleanTypeDefinition) {
            codec = BooleanStringCodec.from((BooleanTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof DecimalTypeDefinition) {
            codec = DecimalStringCodec.from((DecimalTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof EmptyTypeDefinition) {
            codec = EmptyStringCodec.INSTANCE;
        } else if (typeDefinition instanceof EnumTypeDefinition) {
            codec = EnumStringCodec.from((EnumTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof Int8TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Int8TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof Int16TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Int16TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof Int32TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Int32TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof Int64TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Int64TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof StringTypeDefinition) {
            codec = StringStringCodec.from((StringTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof UnionTypeDefinition) {
            codec = UnionStringCodec.from((UnionTypeDefinition)typeDefinition);
        } else if (typeDefinition instanceof Uint8TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Uint8TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof Uint16TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Uint16TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof Uint32TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Uint32TypeDefinition) typeDefinition);
        } else if (typeDefinition instanceof Uint64TypeDefinition) {
            codec = AbstractIntegerStringCodec.from((Uint64TypeDefinition) typeDefinition);
        } else {
            codec = null;
        }
        return codec;
    }
}

@@ -435,16 +435,60 @@
 tional;%0A
+import org.eclipse.jdt.annotation.Nullable;%0A
 import o
@@ -2566,32 +2566,108 @@
 nition);%0A    %7D%0A%0A
+    // FIXME: do we want an Optional or a throws instead of @Nullable here?%0A
     public stati
@@ -2660,32 +2660,42 @@
   public static 
+@Nullable 
 TypeDefinitionAw
@@ -2764,61 +2764,8 @@
 ) %7B%0A
-        final TypeDefinitionAwareCodec%3C?, ?%3E codec;%0A%0A
     
@@ -2834,23 +2834,22 @@
         
-codec =
+return
  BinaryS
@@ -2982,23 +2982,22 @@
         
-codec =
+return
  BitsStr
@@ -3129,23 +3129,22 @@
         
-codec =
+return
  Boolean
@@ -3282,23 +3282,23 @@
         
-codec =
+return 
  Decimal
@@ -3434,23 +3434,22 @@
         
-codec =
+return
  EmptySt
@@ -3547,23 +3547,22 @@
         
-codec =
+return
  EnumStr
@@ -3683,39 +3683,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -3840,39 +3840,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -3998,39 +3998,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -4156,39 +4156,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -4323,23 +4323,22 @@
         
-codec =
+return
  StringS
@@ -4472,23 +4472,22 @@
         
-codec =
+return
  UnionSt
@@ -4611,39 +4611,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -4770,39 +4770,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -4930,39 +4930,38 @@
 ) %7B%0A            
-codec =
+return
  AbstractInteger
@@ -5098,23 +5098,22 @@
         
-codec =
+return
  Abstrac
@@ -5210,15 +5210,14 @@
     
-codec =
+return
  nul
@@ -5233,30 +5233,8 @@
   %7D%0A
-        return codec;%0A
     

Update TypeDefinitionAwareCodec