/*
 * Copyright 2014 NAVER Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.navercorp.pinpoint.common.trace;

/**
 * @author emeroad
 * @author netspider
 * @author Jongho Moon
 */
class DefaultServiceType implements ServiceType {
    private final short code;
    private final String name;
    private final String desc;
    private final boolean terminal;

    // FIXME record statistics of only rpc call currently. so is it all right to chane into isRecordRpc()
    private final boolean recordStatistics;

    // whether or not print out api including destinationId
    private final boolean includeDestinationId;
    private final ServiceTypeCategory category;



    DefaultServiceType(int code, String name, String desc, ServiceTypeProperty... properties) {
        // code must be a short value but constructors accept int to make declaring ServiceType values more cleaner by removing casting to short.
        if (code > Short.MAX_VALUE || code < Short.MIN_VALUE) {
            throw new IllegalArgumentException("code must be a short value");
        }

        this.code = (short)code;
        this.name = name;
        this.desc = desc;

        this.category = ServiceTypeCategory.findCategory((short)code);

        boolean terminal = false;
        boolean recordStatistics = false;
        boolean includeDestinationId = false;
        
        for (ServiceTypeProperty property : properties) {
            switch (property) {
            case TERMINAL:
                terminal = true;
                break;
                
            case RECORD_STATISTICS:
                recordStatistics = true;
                break;
                
            case INCLUDE_DESTINATION_ID:
                includeDestinationId = true;
                break;
            default:
                throw new IllegalStateException("Unknown ServiceTypeProperty:" + property);
            }
        }
        
        this.terminal = terminal;
        this.recordStatistics = recordStatistics;
        this.includeDestinationId = includeDestinationId;
    }


    @Override
    public boolean isInternalMethod() {
        return this == INTERNAL_METHOD;
    }

    @Override
    public boolean isRpcClient() {
        return ServiceTypeCategory.RPC.contains(code);
    }

    // FIXME record statistics of only rpc call currently. so is it all right to chane into isRecordRpc()
    @Override
    public boolean isRecordStatistics() {
        return recordStatistics;
    }

    @Override
    public boolean isUnknown() {
        return this == ServiceType.UNKNOWN; // || this == ServiceType.UNKNOWN_CLOUD;
    }

    // return true when the service type is USER or can not be identified
    @Override
    public boolean isUser() {
        return this == ServiceType.USER;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public short getCode() {
        return code;
    }

    @Override
    public String getDesc() {
        return desc;
    }

    @Override
    public boolean isTerminal() {
        return terminal;
    }

    @Override
    public boolean isIncludeDestinationId() {
        return includeDestinationId;
    }

    @Override
    public ServiceTypeCategory getCategory() {
        return category;
    }

    @Override
    public HistogramSchema getHistogramSchema() {
        return category.getHistogramSchema();
    }

    @Override
    public boolean isWas() {
        return this.category == ServiceTypeCategory.SERVER;
    }
    
    @Override
    public String toString() {
        return desc;
    }

    @Override
    public int hashCode() {
        // ServiceType's hashCode method is not used as they are put into IntHashMap (see ServiceTypeRegistry)
        // which uses ServiceType code as key. It shouldn't really matter what this method returns.
        final int prime = 31;
        int result = 1;
        result = prime * result + code;
        return result;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        
        if (obj == null) {
            return false;
        }
        
        if (getClass() != obj.getClass()) {
            return false;
        }
        
        DefaultServiceType other = (DefaultServiceType) obj;
        if (code != other.code) {
            return false;
        }
        if (desc == null) {
            if (other.desc != null) {
                return false;
            }
        } else if (!desc.equals(other.desc)) {
            return false;
            
        }
        
        if (category == null) {
            if (other.category != null) {
                return false;
            }
        } else if (!category.equals(other.category)) {
            return false;
        }
        
        if (includeDestinationId != other.includeDestinationId) {
            return false;
        }
        
        if (name == null) {
            if (other.name != null) {
                return false;
            }
        } else if (!name.equals(other.name)) {
            return false;
        }
        
        if (recordStatistics != other.recordStatistics) {
            return false;
        }
        
        if (terminal != other.terminal) {
            return false;
        }
        
        return true;
    }

    public static boolean isWas(final short code) {
        return ServiceTypeCategory.SERVER.contains(code);
    }


}

@@ -4135,364 +4135,240 @@
 lic 
-int hashCode() %7B%0A        // ServiceType's hashCode method is not used as they are put into IntHashMap (see ServiceTypeRegistry)%0A        // which uses ServiceType code as key. It shouldn't really matter what this method returns.%0A        final int prime = 31;%0A        int result = 1;%0A        result = prime * result + code;%0A        return result
+boolean equals(Object o) %7B%0A        if (this == o) return true;%0A        if (o == null %7C%7C getClass() != o.getClass()) return false;%0A%0A        DefaultServiceType that = (DefaultServiceType) o;%0A%0A        return code == that.code
 ;%0A
+%0A
     %7D%0A
-    
 %0A
+
     
@@ -4392,1354 +4392,49 @@
 lic 
-boolean equals(Object obj) %7B%0A        if (this == obj) %7B%0A            return true;%0A        %7D%0A        %0A        if (obj == null) %7B%0A            return false;%0A        %7D%0A        %0A        if (getClass() != obj.getClass()) %7B%0A            return false;%0A        %7D%0A        %0A        DefaultServiceType other = (DefaultServiceType) obj;%0A        if (code != other.code) %7B%0A            return false;%0A        %7D%0A        if (desc == null) %7B%0A            if (other.desc != null) %7B%0A                return false;%0A            %7D%0A        %7D else if (!desc.equals(other.desc)) %7B%0A            return false;%0A            %0A        %7D%0A        %0A        if (category == null) %7B%0A            if (other.category != null) %7B%0A                return false;%0A            %7D%0A        %7D else if (!category.equals(other.category)) %7B%0A            return false;%0A        %7D%0A        %0A        if (includeDestinationId != other.includeDestinationId) %7B%0A            return false;%0A        %7D%0A        %0A        if (name == null) %7B%0A            if (other.name != null) %7B%0A                return false;%0A            %7D%0A        %7D else if (!name.equals(other.name)) %7B%0A            return false;%0A        %7D%0A        %0A        if (recordStatistics != other.recordStatistics) %7B%0A            return false;%0A        %7D%0A        %0A        if (terminal != other.terminal) %7B%0A            return false;%0A        %7D%0A        %0A        return tru
+int hashCode() %7B%0A        return (int) cod
 e;%0A 

simplify equal(), hashcode()