/*
 * Copyright 2017, TeamDev Ltd. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.spine3.type;

import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Message;
import org.spine3.base.Command;
import org.spine3.base.Event;
import org.spine3.type.error.UnknownTypeException;

import java.util.regex.Pattern;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
 * Utility class for obtaining a type name from a {@code Message}.
 *
 * @author Alexander Yevsyukov
 */
public class TypeName extends StringTypeValue {

    private static final String PROTOBUF_PACKAGE_SEPARATOR = ".";
    private static final Pattern PROTOBUF_PACKAGE_SEPARATOR_PATTERN =
            Pattern.compile('\\' + PROTOBUF_PACKAGE_SEPARATOR);

    private TypeName(String value) {
        super(value);
    }

    private static TypeName create(String value) {
        return new TypeName(value);
    }

    /**
     * Creates new instance by the passed type name value.
     */
    public static TypeName of(String typeName) {
        checkNotNull(typeName);
        checkArgument(!typeName.isEmpty());
        return create(typeName);
    }

    /**
     * Creates instance from the passed type URL.
     */
    public static TypeName from(TypeUrl typeUrl) {
        checkNotNull(typeUrl);
        return create(typeUrl.getTypeName());
    }

    /**
     * Obtains type name for the passed message.
     */
    public static TypeName of(Message message) {
        checkNotNull(message);
        return from(TypeUrl.of(message));
    }

    /**
     * Obtains type name for the passed message class.
     */
    public static TypeName of(Class<? extends Message> cls) {
        checkNotNull(cls);
        return from(TypeUrl.of(cls));
    }

    /**
     * Obtains type name from the message of the passed command.
     */
    public static TypeName ofCommand(Command command) {
        checkNotNull(command);
        return from(TypeUrl.ofCommand(command));
    }

    /**
     * Obtains type name from the message of the passed event.
     */
    public static TypeName ofEvent(Event event) {
        checkNotNull(event);
        return from(TypeUrl.ofEvent(event));
    }

    /**
     * Obtains type name for the message type by its descriptor.
     */
    public static TypeName from(Descriptor descriptor) {
        checkNotNull(descriptor);
        return from(TypeUrl.from(descriptor));
    }

    /**
     * Returns the unqualified name of the Protobuf type, for example: {@code StringValue}.
     */
    public String getSimpleName() {
        final String typeName = value();
        if (typeName.contains(PROTOBUF_PACKAGE_SEPARATOR)) {
            final String[] parts = PROTOBUF_PACKAGE_SEPARATOR_PATTERN.split(typeName);
            checkState(parts.length > 0, "Invalid type name: " + typeName);
            final String result = parts[parts.length - 1];
            return result;
        } else {
            return typeName;
        }
    }

    /**
     * Creates URL instance corresponding to this type name.
     */
    public TypeUrl toUrl() {
        return TypeUrl.from(this);
    }

    /**
     * Returns a message {@link Class} corresponding to the Protobuf type represented
     * by this type name.
     *
     * @return the message class
     * @throws UnknownTypeException wrapping {@link ClassNotFoundException} if
     *         there is no corresponding Java class
     */
    public <T extends Message> Class<T> getJavaClass() throws UnknownTypeException {
        return KnownTypes.getJavaClass(toUrl());
    }
}

@@ -1036,16 +1036,56 @@
 .type;%0A%0A
+import com.google.common.base.Splitter;%0A
 import c
@@ -1127,16 +1127,16 @@
 riptor;%0A
-
 import c
@@ -1298,21 +1298,12 @@
 til.
-regex.Pattern
+List
 ;%0A%0Ai
@@ -1435,71 +1435,8 @@
 ull;
-%0Aimport static com.google.common.base.Preconditions.checkState;
 %0A%0A/*
@@ -1621,182 +1621,56 @@
 al S
-tring PROTOBUF_PACKAGE_SEPARATOR = %22.%22;%0A    private static final Pattern PROTOBUF_PACKAGE_SEPARATOR_PATTERN =%0A            Pattern.compile('%5C%5C' + PROTOBUF_PACKAGE_SEPARATOR);%0A
+plitter packageSplitter = Splitter.on('.');%0A    
 %0A   
@@ -3515,73 +3515,8 @@
 ();%0A
-        if (typeName.contains(PROTOBUF_PACKAGE_SEPARATOR)) %7B%0A    
     
@@ -3529,142 +3529,58 @@
 nal 
+List%3C
 String
-%5B%5D parts = PROTOBUF_PACKAGE_SEPARATOR_PATTERN.split(typeName);%0A            checkState(parts.length %3E 0, %22Invalid type name: %22 + 
+%3E tokens = packageSplitter.splitToList(
 type
@@ -3582,28 +3582,24 @@
 (typeName);%0A
-    
         fina
@@ -3620,37 +3620,39 @@
 t = 
-parts%5Bparts.length
+tokens.get(tokens.size()
  - 1
-%5D
+)
 ;%0A
-    
     
@@ -3674,64 +3674,8 @@
 lt;%0A
-        %7D else %7B%0A            return typeName;%0A        %7D%0A
     

Simplify getting simple type name