content: /*
   * 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 com.datastax.oss.driver.internal.core.metadata.schema.parsing;
  
  import com.datastax.oss.driver.api.core.CqlIdentifier;
  import com.datastax.oss.driver.api.core.type.DataType;
  import com.datastax.oss.driver.api.core.type.UserDefinedType;
  import com.datastax.oss.driver.internal.core.context.InternalDriverContext;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import net.jcip.annotations.ThreadSafe;
  
  @ThreadSafe
  public class DataTypeClassNameCompositeParser extends DataTypeClassNameParser {
  
    public ParseResult parseWithComposite(
        String className,
        CqlIdentifier keyspaceId,
        Map<CqlIdentifier, UserDefinedType> userTypes,
        InternalDriverContext context) {
      Parser parser = new Parser(className, 0);
  
      String next = parser.parseNextName();
      if (!isComposite(next)) {
        return new ParseResult(parse(keyspaceId, className, userTypes, context), isReversed(next));
      }
  
      List<String> subClassNames = parser.getTypeParameters();
      int count = subClassNames.size();
      String last = subClassNames.get(count - 1);
      Map<String, DataType> collections = new HashMap<>();
      if (isCollection(last)) {
        count--;
        Parser collectionParser = new Parser(last, 0);
        collectionParser.parseNextName(); // skips columnToCollectionType
        Map<String, String> params = collectionParser.getCollectionsParameters();
        for (Map.Entry<String, String> entry : params.entrySet()) {
          collections.put(entry.getKey(), parse(keyspaceId, entry.getValue(), userTypes, context));
        }
      }
  
      List<DataType> types = new ArrayList<>(count);
      List<Boolean> reversed = new ArrayList<>(count);
      for (int i = 0; i < count; i++) {
        types.add(parse(keyspaceId, subClassNames.get(i), userTypes, context));
        reversed.add(isReversed(subClassNames.get(i)));
      }
  
      return new ParseResult(true, types, reversed, collections);
    }
  
    public static class ParseResult {
      public final boolean isComposite;
      public final List<DataType> types;
      public final List<Boolean> reversed;
      public final Map<String, DataType> collections;
  
      private ParseResult(DataType type, boolean reversed) {
        this(
            false,
            Collections.singletonList(type),
            Collections.singletonList(reversed),
            Collections.emptyMap());
      }
  
      private ParseResult(
          boolean isComposite,
          List<DataType> types,
          List<Boolean> reversed,
          Map<String, DataType> collections) {
        this.isComposite = isComposite;
        this.types = types;
        this.reversed = reversed;
        this.collections = collections;
      }
    }
  
    private static boolean isComposite(String className) {
      return className.startsWith("org.apache.cassandra.db.marshal.CompositeType");
    }
  
    private static boolean isCollection(String className) {
      return className.startsWith("org.apache.cassandra.db.marshal.ColumnToCollectionType");
    }
  }
  