package ru.job4j;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Task 5.4.3.
 * Update method add for set
 *
 * Created by Anton Vasilyuk on 17.06.2017.
 * @version 1.0
 */

public class FastAddSet<E> implements Iterable {

    /**.
     * @Cursor is cursor in the set
     */
    private int cursor = 0;

    /**.
     * @cursorIter is location iterator
     */
    private int cursorIter = 0;

    /**.
     * @size is size array for set
     */
    private int size;

    /**.
     * @container is link for set
     */
    private Object[] container;

    /**.
     * Constructor for SimpleSetArray
     * @param aSize
     */
    public FastAddSet(int aSize) {
        this.size = aSize;
        container = new Object[aSize];
    }

    /**.
     * Method for add element to the set
     * @param value is element
     */
    public void addFirst(E value) {
        if (value == null) {throw new NullPointerException("Element is null");}
        boolean check = true;
        for (int i = 0; i < cursor; i++) {
            E temp = (E) container[i];
            if (temp.equals(value)) {check = false;}
        }
        if (check) {
            if(this.cursor < container.length) {
                container[cursor] = value;
                cursor++;
            } else {
                Object[] newConteiner = new Object[size * 2];
                System.arraycopy(container, 0, newConteiner, 0, size);
                container = newConteiner;
                container[size] = value;
                cursor++;
            }
        }
    }

    /**.
     * Method faster Add element to the set
     * @param value is element for adding
     */
    public void addSecond(E value) {
        if (value == null) {throw new NullPointerException("Element is null");}
        if (cursor == 0) {
            container[cursor] = value;
            cursor++;
        } else {
            int position = searchValue(value, container, 0, cursor - 1);

            if (position != -1) {
                if (this.cursor < container.length) {
                    for (int i = cursor; i > position; i--) {
                        container[i] = container[i - 1];
                    }
                    container[position] = value;
                    cursor++;
                } else {
                    Object[] newConteiner = new Object[size * 2];
                    System.arraycopy(container, 0, newConteiner, 0, size);
                    container = newConteiner;
                    for (int i = cursor; i > position; i--) {
                        container[i] = container[i - 1];
                    }
                    container[position] = value;
                    cursor++;
                }
            }
        }
    }

    /**.
     * Realisation iterator
     * @return iterator
     */
    @Override
    public Iterator<E> iterator() {
        Iterator<E> it = (Iterator<E>) new Iterator<Object>() {

            @Override
            public boolean hasNext() {
                return cursorIter < cursor;
            }

            @Override
            public Object next() {
                if (hasNext()) {return container[cursorIter++];}
                else {throw new NoSuchElementException("Need add cell in this array");}
            }

            @Override
            public void remove() {
                container[cursorIter] = null;
                cursorIter--;
            }
        };
        return it;
    }

    /**.
     * Method for search element in the set, and return index for new element
     * @param value is element for adding
     * @param array is array for set
     * @param start is start index
     * @param end is finish index
     * @return return index for the element or -1
     */
    public int searchValue(E value, Object[] array, int start, int end) {
        int result = -1;
        int low = start;
        int high = end;
        int mid = low + (high - low) / 2;
        if (high == low && !array[0].equals(value)) {
            if (value.hashCode() > array[low].hashCode()) {
                return 1;
            } else {
                return 0;
            }
        }

        if (high == low + 1) {
            if (array[low].equals(value) || array[high].equals(value)) {return -1;}
            if (value.hashCode() < array[low].hashCode()) {return 0;}
            else if (value.hashCode() < array[high].hashCode()) {return 1;}
            else {return 2;}
        }

        if (start > end || value == null || array == null) {return -1;}

        if (value.hashCode() < array[mid].hashCode()) {
            if (((mid - 1) - low) == 1 || ((mid - 1) == low)) {
                if (!array[mid - 1].equals(value) && !array[low].equals(value)) {return mid - 1;}}
            return searchValue(value, array, low, mid - 1 );
        } else if (value.hashCode() > array[mid].hashCode()) {
            if ((high - (mid + 1)) == 1 || high == (mid + 1)) {
                if (!array[mid + 1].equals(value) && !array[high].equals(value)) {return high;}}
            return searchValue(value, array, mid + 1, high);
        } else if (array[mid].equals(value)) {return -1;}
        else {return result;}
    }
}

@@ -578,16 +578,110 @@
 ainer;%0A%0A
+    /**.%0A     * @link is link on the SimpleSetArray%0A     */%0A    private SimpleSetArray link;%0A%0A
     /**.
@@ -809,32 +809,37 @@
  aSize;%0A        
+this.
 container = new 
@@ -853,16 +853,63 @@
 aSize%5D;%0A
+        this.link = new SimpleSetArray(aSize);%0A
     %7D%0A%0A 
@@ -1124,600 +1124,57 @@
     
-boolean check = true;%0A        for (int i = 0; i %3C cursor; i++) %7B%0A            E temp = (E) container%5Bi%5D;%0A            if (temp.equals(value)) %7Bcheck = false;%7D%0A        %7D%0A        if (check) %7B%0A            if(this.cursor %3C container.length) %7B%0A                container%5Bcursor%5D = value;%0A                cursor++;%0A            %7D else %7B%0A                Object%5B%5D newConteiner = new Object%5Bsize * 2%5D;%0A                System.arraycopy(container, 0, newConteiner, 0, size);%0A                container = newConteiner;%0A                container%5Bsize%5D = value;%0A                cursor++;%0A            %7D%0A        %7D
+link.add(value);%0A        cursor = link.getSize();
 %0A   
@@ -1409,16 +1409,21 @@
     if (
+this.
 cursor =
@@ -1433,32 +1433,37 @@
 ) %7B%0A            
+this.
 container%5Bcursor
@@ -1477,32 +1477,37 @@
 ue;%0A            
+this.
 cursor++;%0A      
@@ -1704,32 +1704,37 @@
    for (int i = 
+this.
 cursor; i %3E posi
@@ -1762,32 +1762,37 @@
                 
+this.
 container%5Bi%5D = c
@@ -1891,32 +1891,37 @@
                 
+this.
 cursor++;%0A      
@@ -2159,16 +2159,21 @@
 int i = 
+this.
 cursor; 
@@ -2209,32 +2209,37 @@
                 
+this.
 container%5Bi%5D = c
@@ -2342,24 +2342,29 @@
             
+this.
 cursor++;%0A  
@@ -4850,11 +4850,59 @@
 ;%7D%0A    %7D
+%0A%0A    public int getSize() %7Breturn this.cursor;%7D
 %0A%7D%0A

add file for chapter_003_5.4.3