/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cli_fmw.delegate.directory;
import cli_fmw.main.ClipsException;
import cli_fmw.main.DirectoryItemNotFoundException;
import framework.beans.directory.DirectoryItemRecursiveDetails;
import framework.beans.directory.RecursiveLazy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author petr
* @param <BEAN>
* @param <ITEM>
*/
abstract public class DirectoryRecursiveLazy
<BEAN extends RecursiveLazy<? extends DirectoryItemRecursiveDetails>,
ITEM extends DirectoryItemRecursiveLazy<ITEM, ?>>
extends DirectoryRecursive<BEAN, ITEM> {
/**Indexes of loaded items by create path*/
private int[] pathIDs = new int[0];
protected DirectoryRecursiveLazy(String beanName)
throws ClipsException {
super(beanName);
}
@Override
public ITEM getItemFromID(int id) throws DirectoryItemNotFoundException {
ITEM found = super.getItemFromID(id);
if (found != null){
return found;
}else{
try {
List<? extends DirectoryItemRecursiveDetails> path = getBean().get().getPath(id);
List<ITEM> itemList = createPath(path);
return itemList.get(itemList.size()-1);
} catch (Exception ex) {
ex.printStackTrace();
clearBean();
throw new DirectoryItemNotFoundException("Элемент справочника '" + getDirectoryTitle() + "' № " + id + " не найден");
}
}
}
/**
* превращает цепочку деталей в цепочку итемов, недостающие итемы создаёт
* @param path цепочка от корня до итема
*/
private List<ITEM> createPath(List<? extends DirectoryItemRecursiveDetails> path) throws ClipsException{
ITEM parent = null;
ArrayList<ITEM> itemList = new ArrayList<ITEM>();
//relength of loaded ids array
// int l = pathIDs.length;
// pathIDs = Arrays.copyOf(pathIDs, l + path.size());
for (int i = 0; i < path.size(); i++) {
DirectoryItemRecursiveDetails d = path.get(i);
ITEM newItem = findIDX(d.getId());
if (newItem == null) {
newItem = createFromLoadedDetails(d);
itemList.add(newItem);
//add to loaded
// pathIDs[l++] = d.id;
ITEM item = itemList.get(i);
if (parent != null){
parent.addLoadedItem(item);
}else{
if (!isItemLoaded(item.getID())) {
this.addLoadedItem(itemList.get(i));
}else{
// todo подумать надо ли это
// ITEMCLASS findIDX = findIDX(item.getID());
// findIDX.setDetails(item.getDetails());
}
}
}else {
itemList.add(newItem);
}
parent = newItem;
}
Arrays.sort(pathIDs);
return itemList;
}
/**
* Создаёт итем по деталям
* @param details
* @return
*/
final ITEM createItemByDetails(DirectoryItemRecursiveDetails details){
ITEM item = createFromLoadedDetails(details);
item.setDirectory(this);
return item;
}
@Override
public boolean isItemLoaded(int id) {
// if (Arrays.binarySearch(pathIDs, id) < 0){
return super.isItemLoaded(id);
// }else{
// return true;
// }
}
/**
* Проверяет упорядоченность элементов по идентификатьору
* @param items должен содержать не менее 2х элементов
* @return истина если порядок соблюдается
*/
private boolean checkOrder(ArrayList<ITEM> items){
for (int i = 1; i < items.size(); i++) {
if (items.get(i-1).getID() - items.get(i).getID() >= 0){
return false;
}
}
return true;
}
/**
* Добавляет толпой массив итемов
* @param items
*/
protected void addIdxItems(ArrayList<ITEM> items) {
if (items != null && !items.isEmpty()){
if (!checkOrder(items)){
Collections.sort(items, idComparator);
}
//найти место для первого элемента
Map<Integer, List<ITEM>> parentsMap = new HashMap<Integer, List<ITEM>>();
int idx = Collections.binarySearch(idxItems, items.get(0), idComparator);
int dirItemIdx = 0;
int newItemIdx = 0;
if (idx < 0) {
dirItemIdx = (-idx) - 1;
} else {
newItemIdx++;
dirItemIdx = idx + 1;
}
while (newItemIdx < items.size()) {
int compare = 1;
if (dirItemIdx >= idxItems.size()){//если достигнута граница основного массива то пишем ему в конец
dirItemIdx = idxItems.size();
}else{
compare = idComparator.compare(idxItems.get(dirItemIdx), items.get(newItemIdx));
}
if (compare == 0) {//дропнуть повтор
newItemIdx++;
} else if (compare < 0) {//увеличит индекс у первого массива
dirItemIdx++;
} else {//добавить текущий элемент из нового массива и увеличить оба индекса
ITEM current = items.get(newItemIdx);
idxItems.add(dirItemIdx, current);
newItemIdx++;
dirItemIdx++;
int parentId = current.getParentID();
if (parentId > 0) {
if (parentsMap.get(parentId) == null) {
parentsMap.put(parentId, new ArrayList<ITEM>());
}
int point = Collections.binarySearch(parentsMap.get(parentId), current);
if (point < 0){
parentsMap.get(parentId).add(-point-1, current);
}
}
}
}
for (Integer parentId : parentsMap.keySet()) {
ITEM parent = findIDX(parentId);
if (parent != null){
parent.fastAddItemList(parentsMap.get(parentId));
}
}
}
}
}