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 org.apache.chemistry.opencmis.server.impl.browser;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  
  import javax.servlet.http.HttpServletRequest;
  
  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
  import org.apache.chemistry.opencmis.commons.impl.Constants;
  
  /**
   * Parses HTML form controls.
   */
  public class ControlParser {
  
      public static final String CONTROL_PROP_ID_LOWER = "propertyid";
      private static final String CONTROL_PROP_VALUE_LOWER = "propertyvalue";
  
      private final HttpServletRequest request;
  
      private final Map<String, String> zeroDim = new HashMap<String, String>();
      private final Map<String, Map<Integer, String>> oneDim = new HashMap<String, Map<Integer, String>>();
      private final Map<String, Map<Integer, Map<Integer, String>>> twoDim = new HashMap<String, Map<Integer, Map<Integer, String>>>();
  
      public ControlParser(HttpServletRequest request) {
          this.request = request;
          parse();
      }
  
      private void parse() {
          // gather all controls
          Map<String, String[]> controls = request.getParameterMap();
          if (controls == null) {
              return;
          }
  
          for (Map.Entry<String, String[]> control : controls.entrySet()) {
              String controlName = control.getKey().trim().toLowerCase(Locale.ENGLISH);
  
              int firstIndex = getFirstIndex(controlName);
  
              if (firstIndex == -1) {
                  zeroDim.put(controlName, control.getValue()[0]);
              } else {
                  String strippedControlName = controlName.substring(0, controlName.indexOf('['));
                  int secondIndex = getSecondIndex(controlName);
  
                  if (secondIndex == -1) {
                      Map<Integer, String> values = oneDim.get(strippedControlName);
                      if (values == null) {
                          values = new HashMap<Integer, String>();
                          oneDim.put(strippedControlName, values);
                      }
  
                      values.put(firstIndex, control.getValue()[0]);
                  } else {
                      Map<Integer, Map<Integer, String>> values = twoDim.get(strippedControlName);
                      if (values == null) {
                          values = new HashMap<Integer, Map<Integer, String>>();
                          twoDim.put(strippedControlName, values);
                      }
  
                      Map<Integer, String> list = values.get(firstIndex);
                      if (list == null) {
                          list = new HashMap<Integer, String>();
                          values.put(firstIndex, list);
                      }
  
                      list.put(secondIndex, control.getValue()[0]);
                  }
              }
          }
      }
  
      private static int getFirstIndex(String controlName) {
          int result = -1;
  
          int open = controlName.indexOf('[');
          int close = controlName.indexOf(']');
  
          if (open == -1 || close == -1 || close < open) {
              return result;
          }
  
          String indexStr = controlName.substring(open + 1, close);
          try {
              result = Integer.parseInt(indexStr);
              if (result < 0) {
                  result = -1;
              }
          } catch (NumberFormatException e) {
              // return default value (-1)
          }
  
          return result;
      }
  
      private static int getSecondIndex(String controlName) {
          int result = -1;
  
          int open = controlName.indexOf("][");
          int close = controlName.lastIndexOf(']');
  
          if (open == -1 || close == -1 || close < open) {
              return result;
          }
  
          String indexStr = controlName.substring(open + 2, close);
          try {
              result = Integer.parseInt(indexStr);
              if (result < 0) {
                  result = -1;
              }
          } catch (NumberFormatException e) {
              // return default value (-1)
          }
  
          return result;
      }
  
      private static List<String> convertToList(String controlName, Map<Integer, String> map) {
          if (map == null) {
              return null;
          }
  
          int count = map.size();
          List<String> result = new ArrayList<String>(count);
  
          for (int i = 0; i < count; i++) {
              String value = map.get(i);
              if (value == null) {
                  throw new CmisInvalidArgumentException(controlName + " has gaps!");
              }
              result.add(value);
          }
  
          return result;
      }
  
      public String getValue(String controlName) {
          if (controlName == null) {
              throw new IllegalArgumentException("controlName must not be null!");
          }
  
          return zeroDim.get(controlName.toLowerCase(Locale.ENGLISH));
      }
  
      public List<String> getValues(String controlName) {
          if (controlName == null) {
              throw new IllegalArgumentException("controlName must not be null!");
          }
  
          return convertToList(controlName, oneDim.get(controlName.toLowerCase(Locale.ENGLISH)));
      }
  
      public List<String> getValues(String controlName, int index) {
          if (controlName == null) {
              throw new IllegalArgumentException("controlName must not be null!");
          }
  
          Map<Integer, Map<Integer, String>> map = twoDim.get(controlName.toLowerCase(Locale.ENGLISH));
          if (map == null) {
              return null;
          }
  
          return convertToList(controlName, map.get(index));
      }
  
      public Map<Integer, String> getOneDimMap(String controlName) {
          if (controlName == null) {
              throw new IllegalArgumentException("controlName must not be null!");
          }
  
          return oneDim.get(controlName.toLowerCase(Locale.ENGLISH));
      }
  
      public Map<Integer, Map<Integer, String>> getTwoDimMap(String controlName) {
          if (controlName == null) {
              throw new IllegalArgumentException("controlName must not be null!");
          }
  
          return twoDim.get(controlName.toLowerCase(Locale.ENGLISH));
      }
  
      public Map<String, List<String>> getProperties() {
          Map<Integer, String> propertyIds = oneDim.get(CONTROL_PROP_ID_LOWER);
          if (propertyIds == null) {
              return null;
          }
  
          Map<Integer, String> oneDimPropValues = oneDim.get(CONTROL_PROP_VALUE_LOWER);
          Map<Integer, Map<Integer, String>> twoDimPropValues = twoDim.get(CONTROL_PROP_VALUE_LOWER);
  
          int count = propertyIds.size();
          Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
  
          for (int i = 0; i < count; i++) {
              String propertyId = propertyIds.get(i);
              if (propertyId == null) {
                  throw new CmisInvalidArgumentException(Constants.CONTROL_PROP_ID + " has gaps!");
              }
  
              List<String> values = null;
              if (oneDimPropValues != null && oneDimPropValues.containsKey(i)) {
                  values = Collections.singletonList(oneDimPropValues.get(i));
              } else if (twoDimPropValues != null && twoDimPropValues.containsKey(i)) {
                  values = new ArrayList<String>();
  
                  Map<Integer, String> valuesMap = twoDimPropValues.get(i);
                  if (valuesMap != null) {
                      int valueCount = valuesMap.size();
  
                      for (int j = 0; j < valueCount; j++) {
                          String value = valuesMap.get(j);
                          if (value == null) {
                              throw new CmisInvalidArgumentException(Constants.CONTROL_PROP_VALUE + "[" + i
                                      + "] has gaps!");
                          }
  
                          values.add(value);
                      }
                  }
              }
  
              result.put(propertyId, values);
          }
  
          return result;
      }
  }
  