/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.text;

import java.util.EmptyStackException;
import java.util.Iterator;
import net.ranides.assira.collection.ArrayUtils;
import net.ranides.assira.collection.Stack;

/**
 *
 * @author ranides
 */
public class StrBuilder extends AbstractStrBuilder<StrBuilder> {
    
    private String endl;
    private final Stack<ListState> list; 

    public StrBuilder() {
        this.list = new Stack<>();
    }

    public StrBuilder(int initialCapacity) {
        super(initialCapacity);
        this.list = new Stack<>();
    }

    public StrBuilder(String str) {
        super(str);
        this.list = new Stack<>();
    }
    
    public StrBuilder list(String separator) {
        list.push(new ListState(separator));
        return this;
    }
    
    public StrBuilder endlist() {
        try {
            list.pop();
            return this;
        } catch(EmptyStackException _cause) {
            throw new IllegalStateException("Call 'list' first");
        }
    }
    
    @Override
    public StrBuilder clear() {
        list.clear();
        return super.clear();
    }
    
    public StrBuilder item() {
        try {
            ListState state = list.peek();
            if(0 != state.count++) {
                append(state.separator);
            }
            return this;
        } catch(EmptyStackException _cause) {
            throw new IllegalStateException("Call 'list' first");
        }
    }
    
    public StrBuilder items(Object[] array) {
        if(!ArrayUtils.isEmpty(array)) {
            for (Object element : array) { append(element); }
        }
        return this;
    }

    public StrBuilder items(Iterable<?> iterable) {
        if (iterable != null) {
            for(Object item : iterable) { append(item); }
        }
        return this;
    }

    public StrBuilder items(Iterator<?> iterator) {
        if (iterator != null) {
            while (iterator.hasNext()) { append(iterator.next()); }
        }
        return this;
    }

    public StrBuilder items(Object[] array, String separator) {
        if( !ArrayUtils.isEmpty(array) ) {
            list(separator);
            for(Object value : array) { item().append(value); }
            endlist();
        }
        return this;
    }

    public StrBuilder items(Iterable<?> iterable, String separator) {
        if( iterable != null ) {
            list(separator);
            for(Object value : iterable) { item().append(value); }
            endlist();
            
        }
        return this;
    }

    public StrBuilder items(Iterator<?> iterator, String separator) {
        if( iterator != null ) {
            list(separator);
            while (iterator.hasNext()) { item().append(iterator.next()); }
            endlist();
            
        }
        return this;
    }
    
    public StrBuilder endl() {
        if (endl == null)  {
            append(StringUtils.ENDL);
            return self();
        }
        return append(endl);
    }
    
    public StrBuilder setEndl(String newLine) {
        this.endl = newLine;
        return self();
    }
    
    public String left(int length) {
        if (length <= 0) {
            return "";
        } else if (length >= size) {
            return new String(buffer, 0, size);
        } else {
            return new String(buffer, 0, length);
        }
    }

    public String right(int length) {
        if (length <= 0) {
            return "";
        } else if (length >= size) {
            return new String(buffer, 0, size);
        } else {
            return new String(buffer, size - length, length);
        }
    }

    @SuppressWarnings("PMD.AvoidReassigningParameters")
    public String mid(int index, int length) {
        if (index < 0) {
            length += index;
            index = 0;
        }
        if(length <= 0 || index >= size) {
            return "";
        }
        return new String(buffer, index, Math.min(size-index, length));
    }
    
    private static final class ListState {
        public int count;
        public String separator;
        
        public ListState(String separator) {
            this.separator = separator;
        }
    }

}
