/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.sis.metadata.sql;

import java.util.Map;
import java.util.HashMap;
import org.apache.sis.util.iso.Types;


/**
 * Utility methods for handling the inheritance between tables.
 * This features is partially supported in PostgreSQL database.
 *
 * @author desruisseaux
 */
final class TableHierarchy {
    /**
     * Delimiter characters for the table name in identifier. Table names are prefixed to identifiers only if
     * the type represented by the table is a subtype. For example since {@code CI_Organisation} is a subtype
     * of {@code CI_Party}, identifiers for organizations need to be prefixed by {@code {CI_Organisation}} in
     * order allow {@code MetadataSource} to know in which table to search for such party.
     *
     * @see MetadataWriter#isReservedChar(int)
     */
    static final char TYPE_OPEN = '{', TYPE_CLOSE = '}';

    /**
     * Abbreviations for commonly-used tables. We use those abbreviations because table names like
     * {@code "MD_VectorSpatialRepresentation"} consume a lot of space, which leave few spaces left
     * for actual identifiers when we want to limit the length to a relatively small value.
     */
    private static final Map<String,String> ABBREVIATIONS = new HashMap<>(16);

    /**
     * The reverse of {@link #ABBREVIATIONS}.
     */
    private static final Map<String,String> TABLES = new HashMap<>(16);
    static {
        add("MD_VectorSpatialRepresentation", "vec");
        add("MD_GridSpatialRepresentation",   "grd");
        add("MD_Georectified",                "rtf");
        add("MD_Georeferenceable",            "cbl");
        add("MD_DataIdentification",          "dat");
        add("SV_ServiceIdentification",       "srv");
        add("MD_FeatureCatalogueDescription", "cat");
        add("MD_CoverageDescription",         "cov");
        add("MD_ImageDescription",            "img");
        add("MD_SampleDimension",             "sd");
        add("MD_Band",                        "bd");
    }

    /**
     * Adds an abbreviation. For class initialization only.
     */
    private static void add(final String table, final String abbreviation) {
        ABBREVIATIONS.put(table, abbreviation);
        TABLES.put(abbreviation, table);
    }

    /**
     * Do not allow instantiation of this class.
     */
    private TableHierarchy() {
    }

    /**
     * Encode table name in the given identifier.
     */
    static String encode(String table, final String identifier) {
        table = ABBREVIATIONS.getOrDefault(table, table);
        return TYPE_OPEN + table + TYPE_CLOSE + identifier;
    }

    /**
     * If the given identifier specifies a subtype of the given type, then returns that subtype.
     * For example if the given type is {@code Party.class} and the given identifier is
     * {@code "{CI_Organisation}EPSG"}, then this method returns {@code Organisation.class}.
     * Otherwise this method returns {@code type} unchanged.
     */
    static Class<?> subType(Class<?> type, final String identifier) {
        if (identifier.charAt(0) == TYPE_OPEN) {
            final int i = identifier.indexOf(TYPE_CLOSE);
            if (i >= 0) {
                String table = identifier.substring(1, i);
                table = TABLES.getOrDefault(table, table);
                final Class<?> subType = Types.forStandardName(table);
                if (subType != null && type.isAssignableFrom(subType)) {
                    type = subType;
                }
            }
        }
        return type;
    }
}

@@ -2043,18 +2043,18 @@
 shMap%3C%3E(
-16
+25
 );%0A%0A    
@@ -2182,10 +2182,10 @@
 p%3C%3E(
-16
+25
 );%0A 
@@ -2196,16 +2196,124 @@
 tatic %7B%0A
+        add(%22CI_Individual%22,                  %22ind%22);%0A        add(%22CI_Organisation%22,                %22org%22);%0A
         
@@ -2570,16 +2570,17 @@
     %22dat
+a
 %22);%0A    
@@ -2892,21 +2892,449 @@
       %22b
+an
 d%22);%0A
+        add(%22MD_LegalConstraints%22,            %22legal%22);%0A        add(%22MD_SecurityConstraints%22,         %22secu%22);%0A        add(%22EX_GeographicBoundingBox%22,       %22bbox%22);%0A        add(%22EX_BoundingPolygon%22,             %22poly%22);%0A        add(%22EX_GeographicDescription%22,       %22gdsc%22);%0A        add(%22EX_SpatialTemporalExtent%22,       %22ste%22);%0A        add(%22MI_GCPCollection%22,               %22gcp%22);%0A        // TODO: missing quality package.%0A
     %7D%0A%0A 

Add abbreviations for all sub-interfaces found in ISO 19115 except quality package.