MtasDataCollector.java

  1. package mtas.codec.util.collector;

  2. import java.io.IOException;
  3. import java.io.Serializable;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.Collection;
  7. import java.util.HashMap;
  8. import java.util.HashSet;
  9. import java.util.LinkedHashMap;
  10. import java.util.Map;
  11. import java.util.Set;
  12. import java.util.SortedMap;
  13. import java.util.SortedSet;
  14. import java.util.TreeMap;
  15. import java.util.Map.Entry;

  16. import mtas.codec.util.DataCollector;

  17. /**
  18.  * The Class MtasDataCollector.
  19.  *
  20.  * @param <T1> the generic type
  21.  * @param <T2> the generic type
  22.  */
  23. public abstract class MtasDataCollector<T1 extends Number & Comparable<T1>, T2 extends Number & Comparable<T2>>
  24.     implements Serializable {

  25.   /** The Constant serialVersionUID. */
  26.   private static final long serialVersionUID = 1L;

  27.   /** The Constant SEGMENT_SORT_ASC. */
  28.   public static final String SEGMENT_SORT_ASC = "segment_asc";

  29.   /** The Constant SEGMENT_SORT_DESC. */
  30.   public static final String SEGMENT_SORT_DESC = "segment_desc";

  31.   /** The Constant SEGMENT_BOUNDARY_ASC. */
  32.   public static final String SEGMENT_BOUNDARY_ASC = "segment_boundary_asc";

  33.   /** The Constant SEGMENT_BOUNDARY_DESC. */
  34.   public static final String SEGMENT_BOUNDARY_DESC = "segment_boundary_desc";

  35.   /** The Constant SEGMENT_KEY. */
  36.   public static final String SEGMENT_KEY = "key";

  37.   /** The Constant SEGMENT_NEW. */
  38.   public static final String SEGMENT_NEW = "new";

  39.   /** The Constant SEGMENT_KEY_OR_NEW. */
  40.   public static final String SEGMENT_KEY_OR_NEW = "key_or_new";

  41.   /** The Constant SEGMENT_POSSIBLE_KEY. */
  42.   public static final String SEGMENT_POSSIBLE_KEY = "possible_key";

  43.   /** The size. */
  44.   protected int size;

  45.   /** The position. */
  46.   protected int position;

  47.   /** The collector type. */
  48.   // properties collector
  49.   protected String collectorType;

  50.   /** The stats type. */
  51.   protected String statsType;

  52.   /** The data type. */
  53.   protected String dataType;

  54.   /** The stats items. */
  55.   private SortedSet<String> statsItems;

  56.   /** The sort type. */
  57.   protected String sortType;

  58.   /** The sort direction. */
  59.   protected String sortDirection;

  60.   /** The start. */
  61.   protected Integer start;

  62.   /** The number. */
  63.   protected Integer number;

  64.   /** The error number. */
  65.   // error
  66.   protected int[] errorNumber;

  67.   /** The error list. */
  68.   protected HashMap<String, Integer>[] errorList;

  69.   /** The key list. */
  70.   protected String[] keyList;

  71.   /** The source number list. */
  72.   protected int[] sourceNumberList;

  73.   /** The with total. */
  74.   private boolean withTotal;

  75.   /** The segment registration. */
  76.   public transient String segmentRegistration;

  77.   /** The segment key value list. */
  78.   protected transient LinkedHashMap<String, Map<String, T1>> segmentKeyValueList;

  79.   /** The segment recompute key list. */
  80.   public transient Map<String, Set<String>> segmentRecomputeKeyList;

  81.   /** The segment keys. */
  82.   public transient Set<String> segmentKeys;

  83.   /** The segment values boundary. */
  84.   protected transient Map<String, T1> segmentValuesBoundary;

  85.   /** The segment value boundary. */
  86.   protected transient T1 segmentValueBoundary;

  87.   /** The segment value top list last. */
  88.   protected transient Map<String, T1> segmentValueTopListLast;

  89.   /** The segment value top list. */
  90.   protected transient ArrayList<T1> segmentValueTopList;

  91.   /** The segment name. */
  92.   protected transient String segmentName;

  93.   /** The segment number. */
  94.   protected transient int segmentNumber;

  95.   /** The has sub. */
  96.   private boolean hasSub;

  97.   /** The sub collector types. */
  98.   private String[] subCollectorTypes;

  99.   /** The sub data types. */
  100.   private String[] subDataTypes;

  101.   /** The sub stats types. */
  102.   private String[] subStatsTypes;

  103.   /** The sub stats items. */
  104.   private SortedSet<String>[] subStatsItems;

  105.   /** The sub sort types. */
  106.   private String[] subSortTypes;

  107.   /** The sub sort directions. */
  108.   private String[] subSortDirections;

  109.   /** The sub start. */
  110.   private Integer[] subStart;

  111.   /** The sub number. */
  112.   private Integer[] subNumber;

  113.   /** The sub collector list next level. */
  114.   protected MtasDataCollector<?, ?>[] subCollectorListNextLevel = null;

  115.   /** The sub collector next level. */
  116.   protected MtasDataCollector<?, ?> subCollectorNextLevel = null;

  117.   /** The new size. */
  118.   protected transient int newSize;

  119.   /** The new position. */
  120.   protected transient int newPosition;

  121.   /** The new current position. */
  122.   protected transient int newCurrentPosition;

  123.   /** The new current existing. */
  124.   protected transient boolean newCurrentExisting;

  125.   /** The new key list. */
  126.   protected transient String[] newKeyList = null;

  127.   /** The new source number list. */
  128.   protected transient int[] newSourceNumberList = null;

  129.   /** The new error number. */
  130.   protected transient int[] newErrorNumber;

  131.   /** The new error list. */
  132.   protected transient HashMap<String, Integer>[] newErrorList;

  133.   /** The new known key found in segment. */
  134.   public transient Set<String> newKnownKeyFoundInSegment;

  135.   /** The new sub collector types. */
  136.   private transient String[] newSubCollectorTypes;

  137.   /** The new sub data types. */
  138.   private transient String[] newSubDataTypes;

  139.   /** The new sub stats types. */
  140.   private transient String[] newSubStatsTypes;

  141.   /** The new sub stats items. */
  142.   private transient SortedSet<String>[] newSubStatsItems;

  143.   /** The new sub sort types. */
  144.   private transient String[] newSubSortTypes;

  145.   /** The new sub sort directions. */
  146.   private transient String[] newSubSortDirections;

  147.   /** The new sub start. */
  148.   private transient Integer[] newSubStart;

  149.   /** The new sub number. */
  150.   private transient Integer[] newSubNumber;

  151.   /** The new sub collector list next level. */
  152.   // subcollectors next level for adding
  153.   protected transient MtasDataCollector<?, ?>[] newSubCollectorListNextLevel = null;

  154.   /** The new sub collector next level. */
  155.   protected transient MtasDataCollector<?, ?> newSubCollectorNextLevel = null;

  156.   /** The closed. */
  157.   protected transient boolean closed = false;

  158.   /** The result. */
  159.   private transient MtasDataCollectorResult<T1, T2> result = null;

  160.   /**
  161.    * Instantiates a new mtas data collector.
  162.    *
  163.    * @param collectorType the collector type
  164.    * @param dataType the data type
  165.    * @param statsType the stats type
  166.    * @param statsItems the stats items
  167.    * @param sortType the sort type
  168.    * @param sortDirection the sort direction
  169.    * @param start the start
  170.    * @param number the number
  171.    * @param segmentRegistration the segment registration
  172.    * @param boundary the boundary
  173.    * @throws IOException Signals that an I/O exception has occurred.
  174.    */
  175.   @SuppressWarnings("unchecked")
  176.   protected MtasDataCollector(String collectorType, String dataType,
  177.       String statsType, SortedSet<String> statsItems, String sortType,
  178.       String sortDirection, Integer start, Integer number,
  179.       String segmentRegistration, String boundary) throws IOException {
  180.     // set properties
  181.     this.closed = false;
  182.     this.collectorType = collectorType; // data or list
  183.     this.dataType = dataType; // long or double
  184.     this.statsType = statsType; // basic, advanced or full
  185.     this.statsItems = statsItems; // sum, n, all, ...
  186.     this.sortType = sortType;
  187.     this.sortDirection = sortDirection;
  188.     this.start = start;
  189.     this.number = number;
  190.     this.segmentRegistration = segmentRegistration;
  191.     this.withTotal = false;
  192.     if (segmentRegistration != null) {
  193.       segmentKeys = new HashSet<>();
  194.       segmentKeyValueList = new LinkedHashMap<>();
  195.       segmentValuesBoundary = new LinkedHashMap<>();
  196.       segmentValueTopListLast = new LinkedHashMap<>();
  197.       if (segmentRegistration.equals(SEGMENT_BOUNDARY_ASC)
  198.           || segmentRegistration.equals(SEGMENT_BOUNDARY_DESC)) {
  199.         if (boundary != null) {
  200.           segmentValueBoundary = stringToBoundary(boundary);
  201.         } else {
  202.           throw new IOException("did expect boundary with segmentRegistration "
  203.               + segmentRegistration);
  204.         }
  205.       } else if (boundary != null) {
  206.         throw new IOException("didn't expect boundary with segmentRegistration "
  207.             + segmentRegistration);
  208.       }
  209.     }
  210.     // initialize administration
  211.     keyList = new String[0];
  212.     sourceNumberList = new int[0];
  213.     errorNumber = new int[0];
  214.     errorList = (HashMap<String, Integer>[]) new HashMap<?, ?>[0];
  215.     size = 0;
  216.     position = 0;
  217.     // subCollectors properties
  218.     hasSub = false;
  219.     subCollectorTypes = null;
  220.     subDataTypes = null;
  221.     subStatsTypes = null;
  222.     subStatsItems = null;
  223.     subSortTypes = null;
  224.     subSortDirections = null;
  225.     subStart = null;
  226.     subNumber = null;
  227.     subCollectorListNextLevel = null;
  228.     subCollectorNextLevel = null;
  229.   }

  230.   /**
  231.    * Instantiates a new mtas data collector.
  232.    *
  233.    * @param collectorType the collector type
  234.    * @param dataType the data type
  235.    * @param statsType the stats type
  236.    * @param statsItems the stats items
  237.    * @param sortType the sort type
  238.    * @param sortDirection the sort direction
  239.    * @param start the start
  240.    * @param number the number
  241.    * @param subCollectorTypes the sub collector types
  242.    * @param subDataTypes the sub data types
  243.    * @param subStatsTypes the sub stats types
  244.    * @param subStatsItems the sub stats items
  245.    * @param subSortTypes the sub sort types
  246.    * @param subSortDirections the sub sort directions
  247.    * @param subStart the sub start
  248.    * @param subNumber the sub number
  249.    * @param segmentRegistration the segment registration
  250.    * @param boundary the boundary
  251.    * @throws IOException Signals that an I/O exception has occurred.
  252.    */
  253.   protected MtasDataCollector(String collectorType, String dataType,
  254.       String statsType, SortedSet<String> statsItems, String sortType,
  255.       String sortDirection, Integer start, Integer number,
  256.       String[] subCollectorTypes, String[] subDataTypes, String[] subStatsTypes,
  257.       SortedSet<String>[] subStatsItems, String[] subSortTypes,
  258.       String[] subSortDirections, Integer[] subStart, Integer[] subNumber,
  259.       String segmentRegistration, String boundary) throws IOException {
  260.     // initialize
  261.     this(collectorType, dataType, statsType, statsItems, sortType,
  262.         sortDirection, start, number, segmentRegistration, boundary);
  263.     // initialize subCollectors
  264.     if (subCollectorTypes != null) {
  265.       hasSub = true;
  266.       this.subCollectorTypes = subCollectorTypes;
  267.       this.subDataTypes = subDataTypes;
  268.       this.subStatsTypes = subStatsTypes;
  269.       this.subStatsItems = subStatsItems;
  270.       this.subSortTypes = subSortTypes;
  271.       this.subSortDirections = subSortDirections;
  272.       this.subStart = subStart;
  273.       this.subNumber = subNumber;
  274.       if (subCollectorTypes.length > 1) {
  275.         newSubCollectorTypes = Arrays.copyOfRange(subCollectorTypes, 1,
  276.             subCollectorTypes.length);
  277.         newSubDataTypes = Arrays.copyOfRange(subDataTypes, 1,
  278.             subStatsTypes.length);
  279.         newSubStatsTypes = Arrays.copyOfRange(subStatsTypes, 1,
  280.             subStatsTypes.length);
  281.         newSubStatsItems = Arrays.copyOfRange(subStatsItems, 1,
  282.             subStatsItems.length);
  283.         newSubSortTypes = Arrays.copyOfRange(subSortTypes, 1,
  284.             subSortTypes.length);
  285.         newSubSortDirections = Arrays.copyOfRange(subSortDirections, 1,
  286.             subSortDirections.length);
  287.         newSubStart = Arrays.copyOfRange(subStart, 1, subStart.length);
  288.         newSubNumber = Arrays.copyOfRange(subNumber, 1, subNumber.length);
  289.       }
  290.       newSubCollectorListNextLevel = new MtasDataCollector[0];
  291.     }
  292.   }

  293.   /**
  294.    * Merge.
  295.    *
  296.    * @param newDataCollector the new data collector
  297.    * @param map the map
  298.    * @param increaseSourceNumber the increase source number
  299.    * @throws IOException Signals that an I/O exception has occurred.
  300.    */
  301.   abstract public void merge(MtasDataCollector<?, ?> newDataCollector,
  302.       Map<MtasDataCollector<?, ?>, MtasDataCollector<?, ?>> map,
  303.       boolean increaseSourceNumber) throws IOException;

  304.   /**
  305.    * Inits the new list.
  306.    *
  307.    * @param maxNumberOfTerms the max number of terms
  308.    * @param segmentName the segment name
  309.    * @param segmentNumber the segment number
  310.    * @param boundary the boundary
  311.    * @throws IOException Signals that an I/O exception has occurred.
  312.    */
  313.   public void initNewList(int maxNumberOfTerms, String segmentName,
  314.       int segmentNumber, String boundary) throws IOException {
  315.     if (closed) {
  316.       result = null;
  317.       closed = false;
  318.     }
  319.     initNewListBasic(maxNumberOfTerms);
  320.     if (segmentRegistration != null) {
  321.       this.segmentName = segmentName;
  322.       this.segmentNumber = segmentNumber;
  323.       if (!segmentKeyValueList.containsKey(segmentName)) {
  324.         segmentKeyValueList.put(segmentName, new HashMap<String, T1>());
  325.         if (segmentRegistration.equals(SEGMENT_BOUNDARY_ASC)
  326.             || segmentRegistration.equals(SEGMENT_BOUNDARY_DESC)) {
  327.           if (boundary != null) {
  328.             segmentValuesBoundary.put(segmentName,
  329.                 stringToBoundary(boundary, segmentNumber));
  330.           } else {
  331.             throw new IOException("expected boundary");
  332.           }
  333.         } else {
  334.           segmentValuesBoundary.put(segmentName, null);
  335.         }
  336.         segmentValueTopListLast.put(segmentName, null);
  337.       }
  338.       this.segmentValueTopList = new ArrayList<>();
  339.     }
  340.   }

  341.   /**
  342.    * Inits the new list.
  343.    *
  344.    * @param maxNumberOfTerms the max number of terms
  345.    * @throws IOException Signals that an I/O exception has occurred.
  346.    */
  347.   public void initNewList(int maxNumberOfTerms) throws IOException {
  348.     if (closed) {
  349.       result = null;
  350.       closed = false;
  351.     }
  352.     if (segmentRegistration != null) {
  353.       throw new IOException("missing segment name");
  354.     } else {
  355.       initNewListBasic(maxNumberOfTerms);
  356.     }
  357.   }

  358.   /**
  359.    * Inits the new list basic.
  360.    *
  361.    * @param maxNumberOfTerms the max number of terms
  362.    * @throws IOException Signals that an I/O exception has occurred.
  363.    */
  364.   @SuppressWarnings("unchecked")
  365.   private void initNewListBasic(int maxNumberOfTerms) throws IOException {
  366.     if (!closed) {
  367.       position = 0;
  368.       newPosition = 0;
  369.       newCurrentPosition = 0;
  370.       newSize = maxNumberOfTerms + size;
  371.       newKeyList = new String[newSize];
  372.       newSourceNumberList = new int[newSize];
  373.       newErrorNumber = new int[newSize];
  374.       newErrorList = (HashMap<String, Integer>[]) new HashMap<?, ?>[newSize];
  375.       newKnownKeyFoundInSegment = new HashSet<>();
  376.       if (hasSub) {
  377.         newSubCollectorListNextLevel = new MtasDataCollector[newSize];
  378.       }
  379.     } else {
  380.       throw new IOException("already closed");
  381.     }
  382.   }

  383.   /**
  384.    * Increase new list size.
  385.    *
  386.    * @throws IOException Signals that an I/O exception has occurred.
  387.    */
  388.   @SuppressWarnings("unchecked")
  389.   protected void increaseNewListSize() throws IOException {
  390.     if (!closed) {
  391.       String[] tmpNewKeyList = newKeyList;
  392.       int[] tmpNewSourceNumberList = newSourceNumberList;
  393.       int[] tmpNewErrorNumber = newErrorNumber;
  394.       HashMap<String, Integer>[] tmpNewErrorList = newErrorList;
  395.       int tmpNewSize = newSize;
  396.       newSize = 2 * newSize;
  397.       newKeyList = new String[newSize];
  398.       newSourceNumberList = new int[newSize];
  399.       newErrorNumber = new int[newSize];
  400.       newErrorList = (HashMap<String, Integer>[]) new HashMap<?, ?>[newSize];
  401.       System.arraycopy(tmpNewKeyList, 0, newKeyList, 0, tmpNewSize);
  402.       System.arraycopy(tmpNewSourceNumberList, 0, newSourceNumberList, 0,
  403.           tmpNewSize);
  404.       System.arraycopy(tmpNewErrorNumber, 0, newErrorNumber, 0, tmpNewSize);
  405.       System.arraycopy(tmpNewErrorList, 0, newErrorList, 0, tmpNewSize);
  406.       if (hasSub) {
  407.         MtasDataCollector<?, ?>[] tmpNewSubCollectorListNextLevel = newSubCollectorListNextLevel;
  408.         newSubCollectorListNextLevel = new MtasDataCollector[newSize];
  409.         System.arraycopy(tmpNewSubCollectorListNextLevel, 0,
  410.             newSubCollectorListNextLevel, 0, tmpNewSize);
  411.       }
  412.     } else {
  413.       throw new IOException("already closed");
  414.     }
  415.   }

  416.   /**
  417.    * Adds the.
  418.    *
  419.    * @param increaseSourceNumber the increase source number
  420.    * @return the mtas data collector
  421.    * @throws IOException Signals that an I/O exception has occurred.
  422.    */
  423.   protected final MtasDataCollector add(boolean increaseSourceNumber)
  424.       throws IOException {
  425.     if (!closed) {
  426.       if (!collectorType.equals(DataCollector.COLLECTOR_TYPE_DATA)) {
  427.         throw new IOException(
  428.             "collector should be " + DataCollector.COLLECTOR_TYPE_DATA);
  429.       } else {
  430.         if (newPosition > 0) {
  431.           newCurrentExisting = true;
  432.         } else if (position < getSize()) {
  433.           // copy
  434.           newKeyList[0] = keyList[0];
  435.           newSourceNumberList[0] = sourceNumberList[0];
  436.           if (increaseSourceNumber) {
  437.             newSourceNumberList[0]++;
  438.           }
  439.           newErrorNumber[0] = errorNumber[0];
  440.           newErrorList[0] = errorList[0];
  441.           if (hasSub) {
  442.             newSubCollectorNextLevel = subCollectorNextLevel;
  443.           }
  444.           copyToNew(0, 0);
  445.           newPosition = 1;
  446.           position = 1;
  447.           newCurrentExisting = true;
  448.         } else {
  449.           // add key
  450.           newKeyList[0] = DataCollector.COLLECTOR_TYPE_DATA;
  451.           newSourceNumberList[0] = 1;
  452.           newErrorNumber[0] = 0;
  453.           newErrorList[0] = new HashMap<>();
  454.           newPosition = 1;
  455.           newCurrentPosition = newPosition - 1;
  456.           newCurrentExisting = false;
  457.           // ready, only handle sub
  458.           if (hasSub) {
  459.             newSubCollectorNextLevel = DataCollector.getCollector(
  460.                 subCollectorTypes[0], subDataTypes[0], subStatsTypes[0],
  461.                 subStatsItems[0], subSortTypes[0], subSortDirections[0],
  462.                 subStart[0], subNumber[0], newSubCollectorTypes,
  463.                 newSubDataTypes, newSubStatsTypes, newSubStatsItems,
  464.                 newSubSortTypes, newSubSortDirections, newSubStart,
  465.                 newSubNumber, segmentRegistration, null);
  466.           } else {
  467.             newSubCollectorNextLevel = null;
  468.           }
  469.         }
  470.         return newSubCollectorNextLevel;
  471.       }
  472.     } else {
  473.       throw new IOException("already closed");
  474.     }
  475.   }

  476.   /**
  477.    * Adds the.
  478.    *
  479.    * @param key the key
  480.    * @param increaseSourceNumber the increase source number
  481.    * @return the mtas data collector
  482.    * @throws IOException Signals that an I/O exception has occurred.
  483.    */
  484.   protected final MtasDataCollector add(String key,
  485.       boolean increaseSourceNumber) throws IOException {
  486.     if (!closed) {
  487.       if (collectorType.equals(DataCollector.COLLECTOR_TYPE_DATA)) {
  488.         throw new IOException(
  489.             "collector should be " + DataCollector.COLLECTOR_TYPE_LIST);
  490.       } else if (key == null) {
  491.         throw new IOException("key shouldn't be null");
  492.       } else {
  493.         // check previous added
  494.         if ((newPosition > 0)
  495.             && newKeyList[(newPosition - 1)].compareTo(key) >= 0) {
  496.           int i = newPosition;
  497.           do {
  498.             i--;
  499.             if (newKeyList[i].equals(key)) {
  500.               newCurrentPosition = i;
  501.               newCurrentExisting = true;
  502.               if (subDataTypes != null) {
  503.                 return newSubCollectorListNextLevel[newCurrentPosition];
  504.               } else {
  505.                 return null;
  506.               }
  507.             }
  508.           } while ((i > 0) && (newKeyList[i].compareTo(key) > 0));
  509.         }
  510.         // move position in old list
  511.         if (position < getSize()) {
  512.           // just add smaller or equal items
  513.           while (keyList[position].compareTo(key) <= 0) {
  514.             if (newPosition == newSize) {
  515.               increaseNewListSize();
  516.             }
  517.             // copy
  518.             newKeyList[newPosition] = keyList[position];
  519.             newSourceNumberList[newPosition] = sourceNumberList[position];
  520.             newErrorNumber[newPosition] = errorNumber[position];
  521.             newErrorList[newPosition] = errorList[position];
  522.             if (hasSub) {
  523.               newSubCollectorListNextLevel[newPosition] = subCollectorListNextLevel[position];
  524.             }
  525.             copyToNew(position, newPosition);
  526.             newPosition++;
  527.             position++;
  528.             // check if added key from list is right key
  529.             if (newKeyList[(newPosition - 1)].equals(key)) {
  530.               if (increaseSourceNumber) {
  531.                 newSourceNumberList[(newPosition - 1)]++;
  532.               }
  533.               newCurrentPosition = newPosition - 1;
  534.               newCurrentExisting = true;
  535.               // register known key found again in segment
  536.               newKnownKeyFoundInSegment.add(key);
  537.               // ready
  538.               if (hasSub) {
  539.                 return newSubCollectorListNextLevel[newCurrentPosition];
  540.               } else {
  541.                 return null;
  542.               }
  543.               // stop if position exceeds size
  544.             } else if (position == getSize()) {
  545.               break;
  546.             }
  547.           }
  548.         }
  549.         // check size
  550.         if (newPosition == newSize) {
  551.           increaseNewListSize();
  552.         }
  553.         // add key
  554.         newKeyList[newPosition] = key;
  555.         newSourceNumberList[newPosition] = 1;
  556.         newErrorNumber[newPosition] = 0;
  557.         newErrorList[newPosition] = new HashMap<>();
  558.         newPosition++;
  559.         newCurrentPosition = newPosition - 1;
  560.         newCurrentExisting = false;
  561.         // ready, only handle sub
  562.         if (hasSub) {
  563.           newSubCollectorListNextLevel[newCurrentPosition] = DataCollector
  564.               .getCollector(subCollectorTypes[0], subDataTypes[0],
  565.                   subStatsTypes[0], subStatsItems[0], subSortTypes[0],
  566.                   subSortDirections[0], subStart[0], subNumber[0],
  567.                   newSubCollectorTypes, newSubDataTypes, newSubStatsTypes,
  568.                   newSubStatsItems, newSubSortTypes, newSubSortDirections,
  569.                   newSubStart, newSubNumber, segmentRegistration, null);
  570.           return newSubCollectorListNextLevel[newCurrentPosition];
  571.         } else {
  572.           return null;
  573.         }
  574.       }
  575.     } else {
  576.       throw new IOException("already closed");
  577.     }
  578.   }

  579.   /**
  580.    * Copy to new.
  581.    *
  582.    * @param position the position
  583.    * @param newPosition the new position
  584.    */
  585.   protected abstract void copyToNew(int position, int newPosition);

  586.   /**
  587.    * Copy from new.
  588.    */
  589.   protected abstract void copyFromNew();

  590.   /**
  591.    * Compare with boundary.
  592.    *
  593.    * @param value the value
  594.    * @param boundary the boundary
  595.    * @return true, if successful
  596.    * @throws IOException Signals that an I/O exception has occurred.
  597.    */
  598.   protected abstract boolean compareWithBoundary(T1 value, T1 boundary)
  599.       throws IOException;

  600.   /**
  601.    * Last for computing segment.
  602.    *
  603.    * @param value the value
  604.    * @param boundary the boundary
  605.    * @return the t1
  606.    * @throws IOException Signals that an I/O exception has occurred.
  607.    */
  608.   protected abstract T1 lastForComputingSegment(T1 value, T1 boundary)
  609.       throws IOException;

  610.   /**
  611.    * Last for computing segment.
  612.    *
  613.    * @return the t1
  614.    * @throws IOException Signals that an I/O exception has occurred.
  615.    */
  616.   protected abstract T1 lastForComputingSegment() throws IOException;

  617.   /**
  618.    * Boundary for segment.
  619.    *
  620.    * @param segmentName the segment name
  621.    * @return the t1
  622.    * @throws IOException Signals that an I/O exception has occurred.
  623.    */
  624.   protected abstract T1 boundaryForSegment(String segmentName)
  625.       throws IOException;

  626.   /**
  627.    * Boundary for segment computing.
  628.    *
  629.    * @param segmentName the segment name
  630.    * @return the t1
  631.    * @throws IOException Signals that an I/O exception has occurred.
  632.    */
  633.   protected abstract T1 boundaryForSegmentComputing(String segmentName)
  634.       throws IOException;

  635.   /**
  636.    * String to boundary.
  637.    *
  638.    * @param boundary the boundary
  639.    * @param segmentNumber the segment number
  640.    * @return the t1
  641.    * @throws IOException Signals that an I/O exception has occurred.
  642.    */
  643.   protected abstract T1 stringToBoundary(String boundary, Integer segmentNumber)
  644.       throws IOException;

  645.   /**
  646.    * String to boundary.
  647.    *
  648.    * @param boundary the boundary
  649.    * @return the t1
  650.    * @throws IOException Signals that an I/O exception has occurred.
  651.    */
  652.   protected T1 stringToBoundary(String boundary) throws IOException {
  653.     return stringToBoundary(boundary, null);
  654.   }

  655.   /**
  656.    * Close segment key value registration.
  657.    *
  658.    * @throws IOException Signals that an I/O exception has occurred.
  659.    */
  660.   public void closeSegmentKeyValueRegistration() throws IOException {
  661.     if (!closed) {
  662.       if (segmentRegistration != null) {
  663.         Map<String, T1> keyValueList = segmentKeyValueList.get(segmentName);
  664.         T1 tmpSegmentValueBoundary = segmentValuesBoundary.get(segmentName);
  665.         for (Entry<String, T1> entry : keyValueList.entrySet()) {
  666.           if (tmpSegmentValueBoundary == null || compareWithBoundary(
  667.               entry.getValue(), tmpSegmentValueBoundary)) {
  668.             segmentKeys.add(entry.getKey());
  669.           }
  670.         }
  671.       }
  672.     } else {
  673.       throw new IOException("already closed");
  674.     }
  675.   }

  676.   /**
  677.    * Recompute segment keys.
  678.    *
  679.    * @throws IOException Signals that an I/O exception has occurred.
  680.    */
  681.   public void recomputeSegmentKeys() throws IOException {
  682.     if (!closed && segmentRegistration != null) {
  683.       if (segmentRegistration.equals(SEGMENT_SORT_ASC)
  684.           || segmentRegistration.equals(SEGMENT_SORT_DESC)
  685.           || segmentRegistration.equals(SEGMENT_BOUNDARY_ASC)
  686.           || segmentRegistration.equals(SEGMENT_BOUNDARY_DESC)) {

  687.         if (segmentRegistration.equals(SEGMENT_SORT_ASC)
  688.             || segmentRegistration.equals(SEGMENT_SORT_DESC)) {
  689.           segmentKeys.clear();
  690.           // recompute boundaries
  691.           for (Entry<String, Map<String, T1>> entry : segmentKeyValueList
  692.               .entrySet()) {
  693.             T1 tmpSegmentValueBoundary = boundaryForSegment(entry.getKey());
  694.             segmentValuesBoundary.put(entry.getKey(), tmpSegmentValueBoundary);
  695.           }
  696.           // compute adjusted boundaries and compute keys
  697.           for (Entry<String, Map<String, T1>> entry : segmentKeyValueList
  698.               .entrySet()) {
  699.             this.segmentName = entry.getKey();
  700.             Map<String, T1> keyValueList = entry.getValue();
  701.             T1 tmpSegmentValueBoundaryForComputing = boundaryForSegmentComputing(
  702.                 entry.getKey());
  703.             for (Entry<String, T1> subEntry : keyValueList.entrySet()) {
  704.               if (tmpSegmentValueBoundaryForComputing == null
  705.                   || compareWithBoundary(subEntry.getValue(),
  706.                       tmpSegmentValueBoundaryForComputing)) {
  707.                 if (!segmentKeys.contains(subEntry.getKey())) {
  708.                   segmentKeys.add(subEntry.getKey());
  709.                 }
  710.               }
  711.             }
  712.           }
  713.         }

  714.         Map<String, T1> keyValueList;
  715.         Set<String> recomputeKeyList;
  716.         segmentRecomputeKeyList = new LinkedHashMap<>();
  717.         for (String key : segmentKeys) {
  718.           for (Entry<String, Map<String, T1>> entry : segmentKeyValueList
  719.               .entrySet()) {
  720.             keyValueList = entry.getValue();
  721.             if (!keyValueList.containsKey(key)) {
  722.               if (!segmentRecomputeKeyList.containsKey(entry.getKey())) {
  723.                 recomputeKeyList = new HashSet<>();
  724.                 segmentRecomputeKeyList.put(entry.getKey(), recomputeKeyList);
  725.               } else {
  726.                 recomputeKeyList = segmentRecomputeKeyList.get(entry.getKey());
  727.               }
  728.               recomputeKeyList.add(key);
  729.             }
  730.           }
  731.         }
  732.         this.segmentName = null;
  733.       } else {
  734.         throw new IOException(
  735.             "not for segmentRegistration " + segmentRegistration);
  736.       }
  737.     } else {
  738.       throw new IOException("already closed or no segmentRegistration ("
  739.           + segmentRegistration + ")");
  740.     }
  741.   }

  742.   /**
  743.    * Reduce to keys.
  744.    *
  745.    * @param keys the keys
  746.    */
  747.   public abstract void reduceToKeys(Set<String> keys);

  748.   /**
  749.    * Reduce to segment keys.
  750.    */
  751.   public void reduceToSegmentKeys() {
  752.     if (segmentRegistration != null) {
  753.       reduceToKeys(segmentKeys);
  754.     }
  755.   }

  756.   /**
  757.    * Check existence necessary keys.
  758.    *
  759.    * @return true, if successful
  760.    * @throws IOException Signals that an I/O exception has occurred.
  761.    */
  762.   public boolean checkExistenceNecessaryKeys() throws IOException {
  763.     if (!closed) {
  764.       if (segmentRegistration != null) {
  765.         return segmentRecomputeKeyList.size() == 0;
  766.       } else {
  767.         return true;
  768.       }
  769.     } else {
  770.       throw new IOException("already closed");
  771.     }
  772.   }

  773.   /**
  774.    * Validate segment boundary.
  775.    *
  776.    * @param o the o
  777.    * @return true, if successful
  778.    * @throws IOException Signals that an I/O exception has occurred.
  779.    */
  780.   abstract public boolean validateSegmentBoundary(Object o) throws IOException;

  781.   /**
  782.    * Validate with segment boundary.
  783.    *
  784.    * @param value the value
  785.    * @return true, if successful
  786.    * @throws IOException Signals that an I/O exception has occurred.
  787.    */
  788.   protected boolean validateWithSegmentBoundary(T1 value) throws IOException {
  789.     if (!closed && segmentRegistration != null) {
  790.       T1 tmpSegmentValueBoundary = segmentValuesBoundary.get(segmentName);
  791.       if (tmpSegmentValueBoundary == null
  792.           || compareWithBoundary(value, tmpSegmentValueBoundary)) {
  793.         return true;
  794.       }
  795.     }
  796.     return false;
  797.   }

  798.   /**
  799.    * Validate segment value.
  800.    *
  801.    * @param value the value
  802.    * @param maximumNumber the maximum number
  803.    * @param segmentNumber the segment number
  804.    * @return the string
  805.    * @throws IOException Signals that an I/O exception has occurred.
  806.    */
  807.   public String validateSegmentValue(T1 value, int maximumNumber,
  808.       int segmentNumber) throws IOException {
  809.     if (!closed) {
  810.       if (segmentRegistration != null) {
  811.         if (maximumNumber > 0) {
  812.           T1 tmpSegmentValueBoundary = segmentValuesBoundary.get(segmentName);
  813.           if (segmentValueTopList.size() < maximumNumber
  814.               || compareWithBoundary(value, tmpSegmentValueBoundary)) {
  815.             return SEGMENT_KEY_OR_NEW;
  816.           } else if (segmentKeys.size() > newKnownKeyFoundInSegment.size()) {
  817.             return SEGMENT_POSSIBLE_KEY;
  818.           } else {
  819.             return null;
  820.           }
  821.         } else {
  822.           return null;
  823.         }
  824.       } else {
  825.         return null;
  826.       }
  827.     } else {
  828.       throw new IOException("already closed");
  829.     }
  830.   }

  831.   /**
  832.    * Validate segment value.
  833.    *
  834.    * @param key the key
  835.    * @param value the value
  836.    * @param maximumNumber the maximum number
  837.    * @param segmentNumber the segment number
  838.    * @param test the test
  839.    * @return the string
  840.    * @throws IOException Signals that an I/O exception has occurred.
  841.    */
  842.   public String validateSegmentValue(String key, T1 value, int maximumNumber,
  843.       int segmentNumber, boolean test) throws IOException {
  844.     if (!closed) {
  845.       if (segmentRegistration != null) {
  846.         if (maximumNumber > 0) {
  847.           T1 tmpSegmentValueMaxListMin = segmentValueTopListLast
  848.               .get(segmentName);
  849.           T1 tmpSegmentValueBoundary = segmentValuesBoundary.get(segmentName);
  850.           if (segmentValueTopList.size() < maximumNumber) {
  851.             if (!test) {
  852.               segmentKeyValueList.get(segmentName).put(key, value);
  853.               segmentValueTopList.add(value);
  854.               segmentValueTopListLast.put(segmentName,
  855.                   (tmpSegmentValueMaxListMin == null) ? value
  856.                       : lastForComputingSegment(tmpSegmentValueMaxListMin,
  857.                           value));
  858.               if (segmentValueTopList.size() == maximumNumber) {
  859.                 tmpSegmentValueMaxListMin = segmentValueTopListLast
  860.                     .get(segmentName);
  861.                 segmentValueTopListLast.put(segmentName,
  862.                     tmpSegmentValueMaxListMin);
  863.                 segmentValuesBoundary.put(segmentName,
  864.                     boundaryForSegmentComputing(segmentName));
  865.               }
  866.             }
  867.             return segmentKeys.contains(key) ? SEGMENT_KEY : SEGMENT_NEW;
  868.           } else if (compareWithBoundary(value, tmpSegmentValueBoundary)) {
  869.             // System.out.println(key+" "+value+" "+tmpSegmentValueBoundary);
  870.             if (!test) {
  871.               segmentKeyValueList.get(segmentName).put(key, value);
  872.               if (compareWithBoundary(value, tmpSegmentValueMaxListMin)) {
  873.                 segmentValueTopList.add(value);
  874.                 segmentValueTopList.remove(tmpSegmentValueMaxListMin);
  875.                 tmpSegmentValueMaxListMin = lastForComputingSegment();
  876.                 segmentValueTopListLast.put(segmentName,
  877.                     tmpSegmentValueMaxListMin);
  878.                 segmentValuesBoundary.put(segmentName,
  879.                     boundaryForSegmentComputing(segmentName));
  880.               }
  881.             }
  882.             return segmentKeys.contains(key) ? SEGMENT_KEY : SEGMENT_NEW;
  883.           } else if (segmentKeys.contains(key)) {
  884.             if (!test) {
  885.               segmentKeyValueList.get(segmentName).put(key, value);
  886.             }
  887.             return SEGMENT_KEY;
  888.           } else {
  889.             return null;
  890.           }
  891.         } else {
  892.           return null;
  893.         }
  894.       } else {
  895.         return null;
  896.       }
  897.     } else {
  898.       throw new IOException("already closed");
  899.     }
  900.   }

  901.   /**
  902.    * Sets the error.
  903.    *
  904.    * @param newPosition the new position
  905.    * @param errorNumberItem the error number item
  906.    * @param errorListItem the error list item
  907.    * @param currentExisting the current existing
  908.    * @throws IOException Signals that an I/O exception has occurred.
  909.    */
  910.   protected final void setError(int newPosition, int errorNumberItem,
  911.       HashMap<String, Integer> errorListItem, boolean currentExisting)
  912.       throws IOException {
  913.     if (!closed) {
  914.       if (currentExisting) {
  915.         newErrorNumber[newPosition] += errorNumberItem;
  916.         HashMap<String, Integer> item = newErrorList[newPosition];
  917.         for (Entry<String, Integer> entry : errorListItem.entrySet()) {
  918.           if (item.containsKey(entry.getKey())) {
  919.             item.put(entry.getKey(),
  920.                 item.get(entry.getKey()) + entry.getValue());
  921.           } else {
  922.             item.put(entry.getKey(), entry.getValue());
  923.           }
  924.         }
  925.       } else {
  926.         newErrorNumber[newPosition] = errorNumberItem;
  927.         newErrorList[newPosition] = errorListItem;
  928.       }
  929.     } else {
  930.       throw new IOException("already closed");
  931.     }
  932.   }

  933.   /**
  934.    * Sorted and unique.
  935.    *
  936.    * @param keyList the key list
  937.    * @param size the size
  938.    * @return true, if successful
  939.    * @throws IOException Signals that an I/O exception has occurred.
  940.    */
  941.   private boolean sortedAndUnique(String[] keyList, int size)
  942.       throws IOException {
  943.     if (!closed) {
  944.       for (int i = 1; i < size; i++) {
  945.         if (keyList[(i - 1)].compareTo(keyList[i]) >= 0) {
  946.           return false;
  947.         }
  948.       }
  949.       return true;
  950.     } else {
  951.       throw new IOException("already closed");
  952.     }
  953.   }

  954.   /**
  955.    * Compute sort and unique mapping.
  956.    *
  957.    * @param keyList the key list
  958.    * @param size the size
  959.    * @return the int[][]
  960.    * @throws IOException Signals that an I/O exception has occurred.
  961.    */
  962.   private int[][] computeSortAndUniqueMapping(String[] keyList, int size)
  963.       throws IOException {
  964.     if (!closed) {
  965.       if (size > 0) {
  966.         SortedMap<String, int[]> sortedMap = new TreeMap<>();
  967.         for (int i = 0; i < size; i++) {
  968.           if (sortedMap.containsKey(keyList[i])) {
  969.             int[] previousList = sortedMap.get(keyList[i]);
  970.             int[] newList = new int[previousList.length + 1];
  971.             System.arraycopy(previousList, 0, newList, 0, previousList.length);
  972.             newList[previousList.length] = i;
  973.             sortedMap.put(keyList[i], newList);
  974.           } else {
  975.             sortedMap.put(keyList[i], new int[] { i });
  976.           }
  977.         }
  978.         Collection<int[]> values = sortedMap.values();
  979.         int[][] result = new int[sortedMap.size()][];
  980.         return values.toArray(result);
  981.       } else {
  982.         return null;
  983.       }
  984.     } else {
  985.       throw new IOException("already closed");
  986.     }
  987.   }

  988.   /**
  989.    * Remap data.
  990.    *
  991.    * @param mapping the mapping
  992.    * @throws IOException Signals that an I/O exception has occurred.
  993.    */
  994.   protected void remapData(int[][] mapping) throws IOException {
  995.     if (!closed) {
  996.       // remap and merge keys
  997.       String[] newKeyList = new String[mapping.length];
  998.       // process mapping for functions?
  999.       HashMap<MtasDataCollector<?, ?>, MtasDataCollector<?, ?>> map = new HashMap<>();
  1000.       int[] newSourceNumberList = new int[mapping.length];
  1001.       int[] newErrorNumber = new int[mapping.length];
  1002.       @SuppressWarnings("unchecked")
  1003.       HashMap<String, Integer>[] newErrorList = (HashMap<String, Integer>[]) new HashMap<?, ?>[mapping.length];
  1004.       for (int i = 0; i < mapping.length; i++) {
  1005.         newKeyList[i] = keyList[mapping[i][0]];
  1006.         newSourceNumberList[i] = sourceNumberList[mapping[i][0]];
  1007.         for (int j = 0; j < mapping[i].length; j++) {
  1008.           if (j == 0) {
  1009.             newErrorNumber[i] = errorNumber[mapping[i][j]];
  1010.             newErrorList[i] = errorList[mapping[i][j]];
  1011.           } else {
  1012.             newErrorNumber[i] += errorNumber[mapping[i][j]];
  1013.             for (Entry<String, Integer> entry : errorList[mapping[i][j]]
  1014.                 .entrySet()) {
  1015.               if (newErrorList[i].containsKey(entry.getKey())) {
  1016.                 newErrorList[i].put(entry.getKey(),
  1017.                     newErrorList[i].get(entry.getKey()) + entry.getValue());
  1018.               } else {
  1019.                 newErrorList[i].put(entry.getKey(), entry.getValue());
  1020.               }
  1021.             }
  1022.           }
  1023.         }
  1024.       }
  1025.       if (hasSub) {
  1026.         newSubCollectorListNextLevel = new MtasDataCollector<?, ?>[mapping.length];
  1027.         for (int i = 0; i < mapping.length; i++) {
  1028.           for (int j = 0; j < mapping[i].length; j++) {
  1029.             if (j == 0 || newSubCollectorListNextLevel[i] == null) {
  1030.               newSubCollectorListNextLevel[i] = subCollectorListNextLevel[mapping[i][j]];
  1031.             } else {
  1032.               newSubCollectorListNextLevel[i]
  1033.                   .merge(subCollectorListNextLevel[mapping[i][j]], map, false);
  1034.             }
  1035.           }
  1036.         }
  1037.         subCollectorListNextLevel = newSubCollectorListNextLevel;
  1038.       }
  1039.       keyList = newKeyList;
  1040.       sourceNumberList = newSourceNumberList;
  1041.       errorNumber = newErrorNumber;
  1042.       errorList = newErrorList;
  1043.       size = keyList.length;
  1044.       position = 0;
  1045.     } else {
  1046.       throw new IOException("already closed");
  1047.     }
  1048.   }

  1049.   /**
  1050.    * Close new list.
  1051.    *
  1052.    * @throws IOException Signals that an I/O exception has occurred.
  1053.    */
  1054.   public void closeNewList() throws IOException {
  1055.     if (!closed) {
  1056.       if (segmentRegistration != null) {
  1057.         this.segmentName = null;
  1058.       }
  1059.       if (newSize > 0) {
  1060.         // add remaining old
  1061.         while (position < getSize()) {
  1062.           if (newPosition == newSize) {
  1063.             increaseNewListSize();
  1064.           }
  1065.           newKeyList[newPosition] = keyList[position];
  1066.           newSourceNumberList[newPosition] = sourceNumberList[position];
  1067.           newErrorNumber[newPosition] = errorNumber[position];
  1068.           newErrorList[newPosition] = errorList[position];
  1069.           if (hasSub) {
  1070.             newSubCollectorListNextLevel[newPosition] = subCollectorListNextLevel[position];
  1071.           }
  1072.           copyToNew(position, newPosition);
  1073.           position++;
  1074.           newPosition++;
  1075.         }
  1076.         // copy
  1077.         keyList = newKeyList;
  1078.         sourceNumberList = newSourceNumberList;
  1079.         errorNumber = newErrorNumber;
  1080.         errorList = newErrorList;
  1081.         subCollectorListNextLevel = newSubCollectorListNextLevel;
  1082.         copyFromNew();
  1083.         size = newPosition;
  1084.         // sort and merge
  1085.         if (!sortedAndUnique(keyList, getSize())) {
  1086.           remapData(computeSortAndUniqueMapping(keyList, getSize()));
  1087.         }
  1088.       }
  1089.       position = 0;
  1090.       newSize = 0;
  1091.       newPosition = 0;
  1092.       newCurrentPosition = 0;
  1093.     }
  1094.   }

  1095.   /**
  1096.    * Gets the item.
  1097.    *
  1098.    * @param i the i
  1099.    * @return the item
  1100.    */
  1101.   abstract protected MtasDataItem<T1, T2> getItem(int i);

  1102.   /**
  1103.    * Checks for sub.
  1104.    *
  1105.    * @return true, if successful
  1106.    */
  1107.   protected boolean hasSub() {
  1108.     return hasSub;
  1109.   }

  1110.   /**
  1111.    * Error.
  1112.    *
  1113.    * @param error the error
  1114.    * @throws IOException Signals that an I/O exception has occurred.
  1115.    */
  1116.   public abstract void error(String error) throws IOException;

  1117.   /**
  1118.    * Error.
  1119.    *
  1120.    * @param key the key
  1121.    * @param error the error
  1122.    * @throws IOException Signals that an I/O exception has occurred.
  1123.    */
  1124.   public abstract void error(String key, String error) throws IOException;

  1125.   /**
  1126.    * Adds the.
  1127.    *
  1128.    * @param valueSum the value sum
  1129.    * @param valueN the value N
  1130.    * @return the mtas data collector
  1131.    * @throws IOException Signals that an I/O exception has occurred.
  1132.    */
  1133.   public abstract MtasDataCollector add(long valueSum, long valueN)
  1134.       throws IOException;

  1135.   /**
  1136.    * Adds the.
  1137.    *
  1138.    * @param values the values
  1139.    * @param number the number
  1140.    * @return the mtas data collector
  1141.    * @throws IOException Signals that an I/O exception has occurred.
  1142.    */
  1143.   public abstract MtasDataCollector add(long[] values, int number)
  1144.       throws IOException;

  1145.   /**
  1146.    * Adds the.
  1147.    *
  1148.    * @param valueSum the value sum
  1149.    * @param valueN the value N
  1150.    * @return the mtas data collector
  1151.    * @throws IOException Signals that an I/O exception has occurred.
  1152.    */
  1153.   public abstract MtasDataCollector add(double valueSum, long valueN)
  1154.       throws IOException;

  1155.   /**
  1156.    * Adds the.
  1157.    *
  1158.    * @param values the values
  1159.    * @param number the number
  1160.    * @return the mtas data collector
  1161.    * @throws IOException Signals that an I/O exception has occurred.
  1162.    */
  1163.   public abstract MtasDataCollector add(double[] values, int number)
  1164.       throws IOException;

  1165.   /**
  1166.    * Adds the.
  1167.    *
  1168.    * @param key the key
  1169.    * @param valueSum the value sum
  1170.    * @param valueN the value N
  1171.    * @return the mtas data collector
  1172.    * @throws IOException Signals that an I/O exception has occurred.
  1173.    */
  1174.   public abstract MtasDataCollector add(String key, long valueSum, long valueN)
  1175.       throws IOException;

  1176.   /**
  1177.    * Adds the.
  1178.    *
  1179.    * @param key the key
  1180.    * @param values the values
  1181.    * @param number the number
  1182.    * @return the mtas data collector
  1183.    * @throws IOException Signals that an I/O exception has occurred.
  1184.    */
  1185.   public abstract MtasDataCollector add(String key, long[] values, int number)
  1186.       throws IOException;

  1187.   /**
  1188.    * Adds the.
  1189.    *
  1190.    * @param key the key
  1191.    * @param valueSum the value sum
  1192.    * @param valueN the value N
  1193.    * @return the mtas data collector
  1194.    * @throws IOException Signals that an I/O exception has occurred.
  1195.    */
  1196.   public abstract MtasDataCollector add(String key, double valueSum,
  1197.       long valueN) throws IOException;

  1198.   /**
  1199.    * Adds the.
  1200.    *
  1201.    * @param key the key
  1202.    * @param values the values
  1203.    * @param number the number
  1204.    * @return the mtas data collector
  1205.    * @throws IOException Signals that an I/O exception has occurred.
  1206.    */
  1207.   public abstract MtasDataCollector add(String key, double[] values, int number)
  1208.       throws IOException;

  1209.   /*
  1210.    * (non-Javadoc)
  1211.    *
  1212.    * @see java.lang.Object#toString()
  1213.    */
  1214.   @Override
  1215.   public String toString() {
  1216.     StringBuilder text = new StringBuilder();
  1217.     text.append(this.getClass().getSimpleName() + "-" + this.hashCode() + "\n");
  1218.     text.append("\t=== " + collectorType + " - " + statsType + " " + statsItems
  1219.         + " " + hasSub + " ===\n");
  1220.     text.append("\tclosed: " + closed + "\n");
  1221.     text.append("\tkeylist: " + Arrays.asList(keyList) + "\n");
  1222.     text.append("\tsegmentKeys: "
  1223.         + (segmentKeys != null ? segmentKeys.contains("1") : "null") + "\n");
  1224.     return text.toString().trim();
  1225.   }

  1226.   /**
  1227.    * Gets the result.
  1228.    *
  1229.    * @return the result
  1230.    * @throws IOException Signals that an I/O exception has occurred.
  1231.    */
  1232.   public MtasDataCollectorResult<T1, T2> getResult() throws IOException {
  1233.     if (!closed) {
  1234.       close();
  1235.     }
  1236.     return result;
  1237.   }

  1238.   /**
  1239.    * Gets the key list.
  1240.    *
  1241.    * @return the key list
  1242.    * @throws IOException Signals that an I/O exception has occurred.
  1243.    */
  1244.   public Set<String> getKeyList() throws IOException {
  1245.     if (!closed) {
  1246.       close();
  1247.     }
  1248.     return new HashSet<>(Arrays.asList(keyList));
  1249.   }

  1250.   /**
  1251.    * Gets the stats items.
  1252.    *
  1253.    * @return the stats items
  1254.    */
  1255.   public SortedSet<String> getStatsItems() {
  1256.     return statsItems;
  1257.   }

  1258.   /**
  1259.    * Close.
  1260.    *
  1261.    * @throws IOException Signals that an I/O exception has occurred.
  1262.    */
  1263.   @SuppressWarnings({ "rawtypes", "unchecked" })
  1264.   public void close() throws IOException {
  1265.     if (!closed) {
  1266.       closeNewList();
  1267.       if (collectorType.equals(DataCollector.COLLECTOR_TYPE_LIST)) {
  1268.         // compute initial basic list
  1269.         TreeMap<String, MtasDataItem<T1, T2>> basicList = new TreeMap<>();
  1270.         for (int i = 0; i < getSize(); i++) {
  1271.           MtasDataItem<T1, T2> newItem = getItem(i);
  1272.           if (basicList.containsKey(keyList[i])) {
  1273.             newItem.add(basicList.get(keyList[i]));
  1274.           }
  1275.           basicList.put(keyList[i], newItem);
  1276.         }
  1277.         // create result based on basic list
  1278.         result = new MtasDataCollectorResult<>(collectorType, sortType,
  1279.             sortDirection, basicList, start, number);
  1280.         // reduce
  1281.         if (segmentRegistration != null) {
  1282.           if (segmentRegistration.equals(SEGMENT_SORT_ASC)
  1283.               || segmentRegistration.equals(SEGMENT_SORT_DESC)) {
  1284.             reduceToKeys(result.getComparatorList().keySet());
  1285.           } else if (segmentRegistration.equals(SEGMENT_BOUNDARY_ASC)
  1286.               || segmentRegistration.equals(SEGMENT_BOUNDARY_DESC)) {
  1287.             Map<String, MtasDataItemNumberComparator> comparatorList = result
  1288.                 .getComparatorList();
  1289.             HashSet<String> filteredKeySet = new HashSet<>();
  1290.             if (segmentRegistration.equals(SEGMENT_BOUNDARY_ASC)) {
  1291.               for (Entry<String, MtasDataItemNumberComparator> entry : comparatorList
  1292.                   .entrySet()) {
  1293.                 if (entry.getValue().compareTo(segmentValueBoundary) < 0) {
  1294.                   filteredKeySet.add(entry.getKey());
  1295.                 }
  1296.               }
  1297.             } else {
  1298.               for (Entry<String, MtasDataItemNumberComparator> entry : comparatorList
  1299.                   .entrySet()) {
  1300.                 if (entry.getValue().compareTo(segmentValueBoundary) > 0) {
  1301.                   filteredKeySet.add(entry.getKey());
  1302.                 }
  1303.               }
  1304.             }
  1305.             reduceToKeys(filteredKeySet);
  1306.             basicList.keySet().retainAll(filteredKeySet);
  1307.             result = new MtasDataCollectorResult<>(collectorType, sortType,
  1308.                 sortDirection, basicList, start, number);
  1309.           }
  1310.         }
  1311.       } else if (collectorType.equals(DataCollector.COLLECTOR_TYPE_DATA)) {
  1312.         if (getSize() > 0) {
  1313.           result = new MtasDataCollectorResult<>(collectorType, getItem(0));
  1314.         } else {
  1315.           result = new MtasDataCollectorResult<>(collectorType, sortType,
  1316.               sortDirection);
  1317.         }
  1318.       } else {
  1319.         throw new IOException("type " + collectorType + " not supported");
  1320.       }
  1321.       closed = true;
  1322.     }
  1323.   }

  1324.   /**
  1325.    * Gets the collector type.
  1326.    *
  1327.    * @return the collector type
  1328.    */
  1329.   public String getCollectorType() {
  1330.     return collectorType;
  1331.   }

  1332.   /**
  1333.    * Gets the stats type.
  1334.    *
  1335.    * @return the stats type
  1336.    */
  1337.   public String getStatsType() {
  1338.     return statsType;
  1339.   }

  1340.   /**
  1341.    * Gets the data type.
  1342.    *
  1343.    * @return the data type
  1344.    */
  1345.   public String getDataType() {
  1346.     return dataType;
  1347.   }

  1348.   /**
  1349.    * Gets the size.
  1350.    *
  1351.    * @return the size
  1352.    */
  1353.   public int getSize() {
  1354.     return size;
  1355.   }

  1356.   /**
  1357.    * With total.
  1358.    *
  1359.    * @return true, if successful
  1360.    */
  1361.   public boolean withTotal() {
  1362.     return withTotal;
  1363.   }

  1364.   /**
  1365.    * Sets the with total.
  1366.    *
  1367.    * @throws IOException Signals that an I/O exception has occurred.
  1368.    */
  1369.   public void setWithTotal() throws IOException {
  1370.     if (collectorType.equals(DataCollector.COLLECTOR_TYPE_LIST)) {
  1371.       if (segmentName != null) {
  1372.         throw new IOException("can't get total with segmentRegistration");
  1373.       } else {
  1374.         withTotal = true;
  1375.       }
  1376.     } else {
  1377.       throw new IOException(
  1378.           "can't get total for dataCollector of type " + collectorType);
  1379.     }
  1380.   }

  1381. }