com.app.blockydemo.ui.adapter.BrickAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.app.blockydemo.ui.adapter.BrickAdapter.java

Source

/**
 *  Catroid: An on-device visual programming system for Android devices
 *  Copyright (C) 2010-2013 The Catrobat Team
 *  (<http://developer.catrobat.org/credits>)
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *  
 *  An additional term exception under section 7 of the GNU Affero
 *  General Public License, version 3, is available at
 *  http://developer.catrobat.org/license_additional_term
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Affero General Public License for more details.
 *  
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.app.blockydemo.ui.adapter;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Spinner;

import com.app.blockydemo.ProjectManager;
import com.app.blockydemo.R;
import com.app.blockydemo.content.Script;
import com.app.blockydemo.content.Sprite;
import com.app.blockydemo.content.StartScript;
import com.app.blockydemo.content.bricks.AllowedAfterDeadEndBrick;
import com.app.blockydemo.content.bricks.Brick;
import com.app.blockydemo.content.bricks.ChangeVariableBrick;
import com.app.blockydemo.content.bricks.DeadEndBrick;
import com.app.blockydemo.content.bricks.FormulaBrick;
import com.app.blockydemo.content.bricks.MarketplaceBrick;
import com.app.blockydemo.content.bricks.NestingBrick;
import com.app.blockydemo.content.bricks.ScriptBrick;
import com.app.blockydemo.content.bricks.WhenStartedBrick;
import com.app.blockydemo.json.JsonConstructor;
import com.app.blockydemo.ui.ViewSwitchLock;
import com.app.blockydemo.ui.dialogs.CustomAlertDialogBuilder;
import com.app.blockydemo.ui.dialogs.NewVariableDialog;
import com.app.blockydemo.ui.dialogs.ScriptNameDialog;
import com.app.blockydemo.ui.dragndrop.DragAndDropListView;
import com.app.blockydemo.ui.dragndrop.DragAndDropListener;
import com.app.blockydemo.ui.fragment.FormulaEditorFragment;

public class BrickAdapter extends BaseAdapter
        implements DragAndDropListener, OnClickListener, ScriptActivityAdapterInterface {

    private static final String TAG = BrickAdapter.class.getSimpleName();
    private static final int ALPHA_FULL = 255;
    private static final int ALPHA_GREYED = 100;
    private Context context;

    public Context getContext() {
        return context;
    }

    private Sprite sprite;
    private int dragTargetPosition;
    private Brick draggedBrick;
    private DragAndDropListView dragAndDropListView;
    private View insertionView;
    private boolean initInsertedBrick;
    private boolean addingNewBrick;
    private int positionOfInsertedBrick;
    private Script scriptToDelete;

    private boolean firstDrag;
    private int fromBeginDrag;
    private int toEndDrag;
    private boolean retryScriptDragging;
    private boolean showDetails = false;

    private List<Brick> brickList;

    private List<Brick> animatedBricks;
    private List<Brick> checkedBricks = new ArrayList<Brick>();

    private int selectMode;
    private OnBrickCheckedListener onBrickCheckedListener;
    private boolean actionMode = false;

    private Lock viewSwitchLock = new ViewSwitchLock();

    public int listItemCount = 0;

    private int clickItemPosition = 0;

    public BrickAdapter(Context context, Sprite sprite, DragAndDropListView listView) {
        this.context = context;
        this.sprite = sprite;
        dragAndDropListView = listView;
        insertionView = View.inflate(context, R.layout.brick_insert, null);
        initInsertedBrick = false;
        addingNewBrick = false;
        firstDrag = true;
        retryScriptDragging = false;
        animatedBricks = new ArrayList<Brick>();
        this.selectMode = ListView.CHOICE_MODE_NONE;
        initBrickList();
    }

    private JsonConstructor json = new JsonConstructor();

    public void initBrickList() {
        brickList = new ArrayList<Brick>();

        Sprite sprite = ProjectManager.getInstance().getCurrentSprite();

        int numberOfScripts = sprite.getNumberOfScripts();
        for (int scriptPosition = 0; scriptPosition < numberOfScripts; scriptPosition++) {
            Script script = sprite.getScript(scriptPosition);

            brickList.add(script.getScriptBrick());
            script.getScriptBrick().setBrickAdapter(this);
            for (Brick brick : script.getBrickList()) {
                brickList.add(brick);
                brick.setBrickAdapter(this);
            }
        }

        Log.d("Json", json.generateJson().toString());
    }

    public boolean isActionMode() {
        return actionMode;
    }

    public void setActionMode(boolean actionMode) {
        this.actionMode = actionMode;
    }

    public List<Brick> getBrickList() {
        return brickList;
    }

    public void setBrickList(List<Brick> brickList) {
        this.brickList = brickList;
    }

    @Override
    public void drag(int from, int to) {

        if (to < 0 || to >= brickList.size()) {
            to = brickList.size() - 1;
        }
        if (from < 0 || from >= brickList.size()) {
            from = brickList.size() - 1;
        }
        if (draggedBrick == null) {
            draggedBrick = (Brick) getItem(from);
            notifyDataSetChanged();
        }

        if (firstDrag) {
            fromBeginDrag = from;
            firstDrag = false;
        }

        if (draggedBrick instanceof NestingBrick) {
            NestingBrick nestingBrick = (NestingBrick) draggedBrick;
            if (nestingBrick.isInitialized()) {
                to = getDraggedNestingBricksToPosition(nestingBrick, from, to);
            }
        } else if (draggedBrick instanceof ScriptBrick) {
            int currentPosition = to;
            brickList.remove(draggedBrick);
            brickList.add(to, draggedBrick);
            to = getNewPositionForScriptBrick(to, draggedBrick);
            dragTargetPosition = to;
            if (currentPosition != to) {
                retryScriptDragging = true;
            } else {
                retryScriptDragging = false;
            }
        }

        to = getNewPositionIfEndingBrickIsThere(to, draggedBrick);

        if (!(draggedBrick instanceof ScriptBrick)) {
            if (to != 0) {
                dragTargetPosition = to;
            } else {
                dragTargetPosition = 1;
                to = 1;
            }
        }

        brickList.remove(draggedBrick);
        brickList.add(dragTargetPosition, draggedBrick);

        toEndDrag = to;

        animatedBricks.clear();

        notifyDataSetChanged();
    }

    private int getNewPositionIfEndingBrickIsThere(int to, Brick brick) {
        int currentPosition = brickList.indexOf(brick);

        if (getItem(to) instanceof AllowedAfterDeadEndBrick && !(getItem(to) instanceof DeadEndBrick)
                && getItem(to - 1) instanceof DeadEndBrick) {
            if (currentPosition > to) {
                return to + 1;
            } else {
                return to;
            }
        } else if (getItem(to) instanceof DeadEndBrick) {
            for (int i = to - 1; i >= 0; i--) {
                if (!(getItem(i) instanceof DeadEndBrick)) {
                    if (currentPosition > i) {
                        return i + 1;
                    } else {
                        return i;
                    }
                }
            }
        }

        return to;
    }

    private int getDraggedNestingBricksToPosition(NestingBrick nestingBrick, int from, int to) {
        List<NestingBrick> nestingBrickList = nestingBrick.getAllNestingBrickParts(true);
        int restrictedTop = 0;
        int restrictedBottom = brickList.size();

        int tempPosition;
        int currentPosition = to;
        boolean passedBrick = false;
        for (NestingBrick temp : nestingBrickList) {
            tempPosition = brickList.indexOf(temp);
            if (temp != nestingBrick) {
                if (!passedBrick) {
                    restrictedTop = tempPosition;
                }
                if (passedBrick) {
                    restrictedBottom = tempPosition;
                    break;
                }
            } else {
                passedBrick = true;
                currentPosition = tempPosition;
            }
        }

        for (int i = currentPosition; i > restrictedTop; i--) {
            if (checkIfScriptOrOtherNestingBrick(brickList.get(i), nestingBrickList)) {
                restrictedTop = i;
                break;
            }
        }

        for (int i = currentPosition; i < restrictedBottom; i++) {
            if (checkIfScriptOrOtherNestingBrick(brickList.get(i), nestingBrickList)) {
                restrictedBottom = i;
                break;
            }
        }

        to = to <= restrictedTop ? restrictedTop + 1 : to;
        to = to >= restrictedBottom ? restrictedBottom - 1 : to;

        return to;
    }

    private boolean checkIfScriptOrOtherNestingBrick(Brick brick, List<NestingBrick> nestingBrickList) {
        if (brick instanceof ScriptBrick) {
            return true;
        }
        if (brick instanceof NestingBrick && !nestingBrickList.contains(brick)) {
            return true;
        }

        return false;
    }

    @Override
    public void drop() {
        int to = toEndDrag;

        if (to < 0 || to >= brickList.size()) {
            to = brickList.size() - 1;
        }

        if (retryScriptDragging || to != getNewPositionForScriptBrick(to, draggedBrick)) {
            scrollToPosition(dragTargetPosition);
            draggedBrick = null;
            initInsertedBrick = true;
            positionOfInsertedBrick = dragTargetPosition;
            notifyDataSetChanged();

            retryScriptDragging = false;
            return;
        }
        int tempTo = getNewPositionIfEndingBrickIsThere(to, draggedBrick);
        if (to != tempTo) {
            to = tempTo;
        }

        if (addingNewBrick) {
            if (draggedBrick instanceof ScriptBrick) {
                addScriptToProject(to, (ScriptBrick) draggedBrick);
            } else {
                addBrickToPosition(to, draggedBrick);
            }

            addingNewBrick = false;
        } else {
            moveExistingProjectBrick(fromBeginDrag, toEndDrag);
        }

        draggedBrick = null;
        firstDrag = true;

        initBrickList();
        notifyDataSetChanged();

        int scrollTo = to;
        if (scrollTo >= brickList.size() - 1) {
            scrollTo = getCount() - 1;
        }
        dragAndDropListView.smoothScrollToPosition(scrollTo);
    }

    private void addScriptToProject(int position, ScriptBrick scriptBrick) {
        Sprite currentSprite = ProjectManager.getInstance().getCurrentSprite();

        int[] temp = getScriptAndBrickIndexFromProject(position);

        int scriptPosition = temp[0];
        int brickPosition = temp[1];
        Script newScript;

        if (scriptBrick.isInitialized()) {
            newScript = scriptBrick.initScript(currentSprite);
            if (currentSprite.getNumberOfBricks() > 0) {
                int addScriptTo = position == 0 ? 0 : scriptPosition + 1;
                currentSprite.addScript(addScriptTo, newScript);
            } else {
                currentSprite.addScript(newScript);
            }
        } else {
            newScript = scriptBrick.initScript(currentSprite);
            if (currentSprite.getNumberOfBricks() > 0) {
                int addScriptTo = position == 0 ? 0 : scriptPosition + 1;
                currentSprite.addScript(addScriptTo, newScript);
            } else {
                currentSprite.addScript(newScript);
            }

            Script previousScript = currentSprite.getScript(scriptPosition);
            if (previousScript != null) {
                Brick brick;
                int size = previousScript.getBrickList().size();
                for (int i = brickPosition; i < size; i++) {
                    brick = previousScript.getBrick(brickPosition);
                    previousScript.removeBrick(brick);
                    newScript.addBrick(brick);
                }
            }
        }

        ProjectManager.getInstance().setCurrentScript(newScript);
    }

    private void moveExistingProjectBrick(int from, int to) {
        Sprite currentSprite = ProjectManager.getInstance().getCurrentSprite();

        int[] tempFrom = getScriptAndBrickIndexFromProject(from);
        int scriptPositionFrom = tempFrom[0];
        int brickPositionFrom = tempFrom[1];

        Script fromScript = currentSprite.getScript(scriptPositionFrom);

        Brick brick = fromScript.getBrick(brickPositionFrom);
        if (draggedBrick != brick) {
            Log.e(TAG, "Want to save wrong brick");
            return;
        }
        fromScript.removeBrick(brick);

        int[] tempTo = getScriptAndBrickIndexFromProject(to);
        int scriptPositionTo = tempTo[0];
        int brickPositionTo = tempTo[1];

        Script toScript = currentSprite.getScript(scriptPositionTo);

        toScript.addBrick(brickPositionTo, brick);
    }

    private void addBrickToPosition(int position, Brick brick) {
        Sprite currentSprite = ProjectManager.getInstance().getCurrentSprite();

        int[] temp = getScriptAndBrickIndexFromProject(position);

        int scriptPosition = temp[0];
        int brickPosition = temp[1];

        Script script = currentSprite.getScript(scriptPosition);

        if (brick instanceof NestingBrick) {
            ((NestingBrick) draggedBrick).initialize();
            List<NestingBrick> nestingBrickList = ((NestingBrick) draggedBrick).getAllNestingBrickParts(true);
            for (int i = 0; i < nestingBrickList.size(); i++) {
                if (nestingBrickList.get(i) instanceof DeadEndBrick) {
                    if (i < nestingBrickList.size() - 1) {
                        Log.w(TAG, "Adding a DeadEndBrick in the middle of the NestingBricks");
                    }
                    position = getPositionForDeadEndBrick(position);
                    temp = getScriptAndBrickIndexFromProject(position);
                    script.addBrick(temp[1], nestingBrickList.get(i));
                } else {
                    script.addBrick(brickPosition + i, nestingBrickList.get(i));
                }
            }
        } else if (brick instanceof ScriptBrick) {

            List<Brick> nestingBrickList = ((ScriptBrick) draggedBrick).getAllNestingBrickParts(true);
            for (int i = 0; i < nestingBrickList.size(); i++) {
                if (nestingBrickList.get(i) instanceof DeadEndBrick) {
                    if (i < nestingBrickList.size() - 1) {
                        Log.w(TAG, "Adding a DeadEndBrick in the middle of the NestingBricks");
                    }
                    position = getPositionForDeadEndBrick(position);
                    temp = getScriptAndBrickIndexFromProject(position);
                    script.addBrick(temp[1], nestingBrickList.get(i));
                } else {
                    script.addBrick(brickPosition + i, nestingBrickList.get(i));
                }
            }
        } else {
            script.addBrick(brickPosition, brick);
        }
    }

    private int getPositionForDeadEndBrick(int position) {
        for (int i = position + 1; i < brickList.size(); i++) {
            if (brickList.get(i) instanceof AllowedAfterDeadEndBrick || brickList.get(i) instanceof DeadEndBrick) {
                return i;
            }

            if (brickList.get(i) instanceof NestingBrick) {
                List<NestingBrick> tempList = ((NestingBrick) brickList.get(i)).getAllNestingBrickParts(true);
                int currentPosition = i;
                i = brickList.indexOf(tempList.get(tempList.size() - 1)) + 1;
                if (i < 0) {
                    i = currentPosition;
                } else if (i >= brickList.size()) {
                    return brickList.size();
                }
            }

            if (brickList.get(i) instanceof AllowedAfterDeadEndBrick || brickList.get(i) instanceof DeadEndBrick) {
                return i;
            }
        }

        return brickList.size();
    }

    private int[] getScriptAndBrickIndexFromProject(int position) {
        int[] returnValue = new int[2];

        if (position >= brickList.size()) {

            returnValue[0] = sprite.getNumberOfScripts() - 1;
            if (returnValue[0] < 0) {
                returnValue[0] = 0;
                returnValue[1] = 0;
            } else {
                Script script = sprite.getScript(returnValue[0]);
                if (script != null) {
                    returnValue[1] = script.getBrickList().size();
                } else {
                    returnValue[1] = 0;
                }
            }

            return returnValue;
        }

        int scriptPosition = 0;
        int scriptOffset;
        for (scriptOffset = 0; scriptOffset < position;) {
            scriptOffset += sprite.getScript(scriptPosition).getBrickList().size() + 1;
            if (scriptOffset < position) {
                scriptPosition++;
            }
        }
        scriptOffset -= sprite.getScript(scriptPosition).getBrickList().size();

        returnValue[0] = scriptPosition;
        List<Brick> brickListFromProject = sprite.getScript(scriptPosition).getBrickList();
        int brickPosition = position;
        if (scriptOffset > 0) {
            brickPosition -= scriptOffset;
        }

        Brick brickFromProject;
        if (brickListFromProject.size() != 0 && brickPosition < brickListFromProject.size()) {
            brickFromProject = brickListFromProject.get(brickPosition);
        } else {
            brickFromProject = null;
        }

        returnValue[1] = sprite.getScript(scriptPosition).getBrickList().indexOf(brickFromProject);
        if (returnValue[1] < 0) {
            returnValue[1] = sprite.getScript(scriptPosition).getBrickList().size();
        }

        return returnValue;
    }

    private void scrollToPosition(final int position) {
        DragAndDropListView list = dragAndDropListView;
        if (list.getFirstVisiblePosition() < position && position < list.getLastVisiblePosition()) {
            return;
        }

        list.setIsScrolling();
        if (position <= list.getFirstVisiblePosition()) {
            list.smoothScrollToPosition(0, position + 2);
        } else {
            list.smoothScrollToPosition(brickList.size() - 1, position - 2);
        }

    }

    public void addNewBrick(int position, Brick brickToBeAdded, boolean initInsertedBrick) {

        if (draggedBrick != null) {
            Log.w(TAG, "Want to add Brick while there is another one currently dragged.");
            return;
        }

        Sprite currentSprite = ProjectManager.getInstance().getCurrentSprite();
        int scriptCount = currentSprite.getNumberOfScripts();
        if (scriptCount == 0 && brickToBeAdded instanceof ScriptBrick) {
            currentSprite.addScript(((ScriptBrick) brickToBeAdded).initScript(currentSprite));
            initBrickList();
            notifyDataSetChanged();
            return;
        }

        if (position < 0) {
            position = 0;
        } else if (position > brickList.size()) {
            position = brickList.size();
        }

        if (brickToBeAdded instanceof ScriptBrick) {

            brickList.add(position, brickToBeAdded);
            position = getNewPositionForScriptBrick(position, brickToBeAdded);
            brickList.remove(brickToBeAdded);
            brickList.add(position, brickToBeAdded);
            scrollToPosition(position);

        } else {

            position = getNewPositionIfEndingBrickIsThere(position, brickToBeAdded);
            position = position <= 0 ? 1 : position;
            position = position > brickList.size() ? brickList.size() : position;
            brickList.add(position, brickToBeAdded);

        }

        this.initInsertedBrick = initInsertedBrick;
        this.positionOfInsertedBrick = position;

        if (scriptCount == 0) {
            Script script = new StartScript(currentSprite);
            currentSprite.addScript(script);
            brickList.add(0, script.getScriptBrick());
            ProjectManager.getInstance().setCurrentScript(script);
            positionOfInsertedBrick = 1;
        }

        notifyDataSetChanged();
    }

    private int getNewPositionForScriptBrick(int position, Brick brick) {
        if (brickList.size() == 0) {
            return 0;
        }
        if (!(brick instanceof ScriptBrick)) {
            return position;
        }

        int lastPossiblePosition = position;
        int nextPossiblePosition = position;

        for (int i = position; i < brickList.size(); i++) {
            if (brickList.get(i) instanceof NestingBrick) {
                List<NestingBrick> bricks = ((NestingBrick) brickList.get(i)).getAllNestingBrickParts(true);
                int beginningPosition = brickList.indexOf(bricks.get(0));
                int endingPosition = brickList.indexOf(bricks.get(bricks.size() - 1));
                if (position >= beginningPosition && position <= endingPosition) {
                    lastPossiblePosition = beginningPosition;
                    nextPossiblePosition = endingPosition;
                    i = endingPosition;
                }
            }

            if (brickList.get(i) instanceof ScriptBrick && brickList.get(i) != brick) {
                break;
            }
        }

        if (position <= lastPossiblePosition) {
            return position;
        } else if (position - lastPossiblePosition < nextPossiblePosition - position) {
            return lastPossiblePosition;
        } else {
            return nextPossiblePosition;
        }
    }

    @Override
    public void remove(int iWillBeIgnored) {
        // list will not be changed until user action ACTION_UP - therefore take the value from the begin
        removeFromBrickListAndProject(fromBeginDrag, false);
    }

    public void removeFromBrickListAndProject(int index, boolean removeScript) {
        if (addingNewBrick) {
            brickList.remove(draggedBrick);
        } else {
            int[] temp = getScriptAndBrickIndexFromProject(index);
            Script script = ProjectManager.getInstance().getCurrentSprite().getScript(temp[0]);
            if (script != null) {

                Brick brick = script.getBrick(temp[1]);
                if (brick instanceof NestingBrick) {
                    for (Brick tempBrick : ((NestingBrick) brick).getAllNestingBrickParts(true)) {
                        script.removeBrick(tempBrick);
                    }
                } else {
                    script.removeBrick(brick);
                }
                if (removeScript) {
                    brickList.remove(script);
                }
            }
        }

        firstDrag = true;
        draggedBrick = null;
        addingNewBrick = false;

        initBrickList();
        notifyDataSetChanged();
    }

    public void removeDraggedBrick() {
        if (!addingNewBrick) {
            draggedBrick = null;
            firstDrag = true;
            notifyDataSetChanged();

            return;
        }

        brickList.remove(draggedBrick);

        firstDrag = true;
        draggedBrick = null;
        addingNewBrick = false;

        initBrickList();
        notifyDataSetChanged();
    }

    public OnLongClickListener getOnLongClickListener() {
        return dragAndDropListView;
    }

    @Override
    public int getCount() {
        return brickList.size();
    }

    @Override
    public Object getItem(int element) {
        if (element < 0 || element >= brickList.size()) {
            return null;
        }
        return brickList.get(element);
    }

    @Override
    public long getItemId(int index) {
        return index;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (draggedBrick != null && dragTargetPosition == position) {
            return insertionView;
        }
        listItemCount = position + 1;

        Object item = getItem(position);

        if (item instanceof ScriptBrick && (!initInsertedBrick || position != positionOfInsertedBrick)) {
            View scriptBrickView = ((Brick) item).getView(context, position, this);
            if (draggedBrick == null) {
                scriptBrickView.setOnClickListener(this);
            }
            return scriptBrickView;
        }

        View currentBrickView;
        // dirty HACK
        // without the footer, position can be 0, and list.get(-1) caused an Indexoutofboundsexception
        // no clean solution was found
        if (position == 0) {
            if (item instanceof AllowedAfterDeadEndBrick && brickList.get(position) instanceof DeadEndBrick) {
                currentBrickView = ((AllowedAfterDeadEndBrick) item).getNoPuzzleView(context, position, this);
            } else {
                currentBrickView = ((Brick) item).getView(context, position, this);
            }
        } else {
            if (item instanceof AllowedAfterDeadEndBrick && brickList.get(position - 1) instanceof DeadEndBrick) {
                currentBrickView = ((AllowedAfterDeadEndBrick) item).getNoPuzzleView(context, position, this);
            } else {
                currentBrickView = ((Brick) item).getView(context, position, this);
            }
        }

        // this one is working but causes null pointer exceptions on movement and control bricks?!
        //      currentBrickView.setOnLongClickListener(longClickListener);

        // Hack!!!
        // if wrapper isn't used the longClick event won't be triggered
        ViewGroup wrapper = (ViewGroup) View.inflate(context, R.layout.brick_wrapper, null);
        if (currentBrickView.getParent() != null) {
            ((ViewGroup) currentBrickView.getParent()).removeView(currentBrickView);
        }

        wrapper.addView(currentBrickView);
        if (draggedBrick == null) {
            if ((selectMode == ListView.CHOICE_MODE_NONE)) {
                wrapper.setOnClickListener(this);
                if (!(item instanceof DeadEndBrick)) {
                    wrapper.setOnLongClickListener(dragAndDropListView);
                }
            }
        }

        if (position == positionOfInsertedBrick && initInsertedBrick && (selectMode == ListView.CHOICE_MODE_NONE)) {
            initInsertedBrick = false;
            addingNewBrick = true;
            dragAndDropListView.setInsertedBrick(position);

            dragAndDropListView.setDraggingNewBrick();
            dragAndDropListView.onLongClick(currentBrickView);

            return insertionView;
        }

        if (animatedBricks.contains(brickList.get(position))) {
            Animation animation = AnimationUtils.loadAnimation(context, R.anim.blink);
            wrapper.startAnimation(animation);
            animatedBricks.remove(brickList.get(position));
        }
        return wrapper;
    }

    public void updateProjectBrickList() {
        initBrickList();
        notifyDataSetChanged();
    }

    @Override
    public void setTouchedScript(int index) {
        if (index >= 0 && index < brickList.size() && brickList.get(index) instanceof ScriptBrick
                && draggedBrick == null) {
            int scriptIndex = getScriptIndexFromProject(index);
            ProjectManager.getInstance().setCurrentScript(sprite.getScript(scriptIndex));
        }
    }

    private int getScriptIndexFromProject(int index) {
        int scriptIndex = 0;
        for (int i = 0; i < index;) {

            i += sprite.getScript(scriptIndex).getBrickList().size() + 1;
            if (i <= index) {
                scriptIndex++;
            }
        }

        return scriptIndex;
    }

    public int getChildCountFromLastGroup() {
        return ProjectManager.getInstance().getCurrentSprite().getScript(getScriptCount() - 1).getBrickList()
                .size();
    }

    public Brick getChild(int scriptPosition, int brickPosition) {
        Sprite sprite = ProjectManager.getInstance().getCurrentSprite();

        return sprite.getScript(scriptPosition).getBrick(brickPosition);
    }

    public int getScriptCount() {
        return ProjectManager.getInstance().getCurrentSprite().getNumberOfScripts();
    }

    @Override
    public void onClick(final View view) {
        if (!viewSwitchLock.tryLock()) {
            return;
        }

        animatedBricks.clear();
        final int itemPosition = calculateItemPositionAndTouchPointY(view);
        final List<CharSequence> items = new ArrayList<CharSequence>();

        if (brickList.get(itemPosition) instanceof ScriptBrick) {
            int scriptIndex = getScriptIndexFromProject(itemPosition);
            ProjectManager.getInstance().setCurrentScript(sprite.getScript(scriptIndex));
        }

        if (!(brickList.get(itemPosition) instanceof DeadEndBrick)
                && !(brickList.get(itemPosition) instanceof ScriptBrick)) {
            items.add(context.getText(R.string.brick_context_dialog_move_brick));
        }
        if (brickList.get(itemPosition) instanceof NestingBrick) {
            items.add(context.getText(R.string.brick_context_dialog_animate_bricks));
        }
        if (!(brickList.get(itemPosition) instanceof ScriptBrick)) {
            items.add(context.getText(R.string.brick_context_dialog_copy_brick));
            items.add(context.getText(R.string.brick_context_dialog_delete_brick));
        } else {
            items.add(context.getText(R.string.brick_context_dialog_edit_script_name));
            items.add(context.getText(R.string.brick_context_dialog_delete_script));
        }
        if (brickList.get(itemPosition) instanceof FormulaBrick) {
            items.add(context.getText(R.string.brick_context_dialog_formula_edit_brick));
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(context);

        boolean drawingCacheEnabled = view.isDrawingCacheEnabled();
        view.setDrawingCacheEnabled(true);
        view.setDrawingCacheBackgroundColor(Color.TRANSPARENT);
        view.buildDrawingCache(true);

        if (view.getDrawingCache() != null) {
            Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
            view.setDrawingCacheEnabled(drawingCacheEnabled);

            ImageView imageView = dragAndDropListView.getGlowingBorder(bitmap);
            builder.setCustomTitle(imageView);
        }

        builder.setItems(items.toArray(new CharSequence[items.size()]), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                CharSequence clickedItemText = items.get(item);
                if (clickedItemText.equals(context.getText(R.string.brick_context_dialog_move_brick))) {
                    view.performLongClick();
                } else if (clickedItemText.equals(context.getText(R.string.brick_context_dialog_copy_brick))) {
                    copyBrickListAndProject(itemPosition);
                } else if (clickedItemText.equals(context.getText(R.string.brick_context_dialog_delete_brick))
                        || clickedItemText.equals(context.getText(R.string.brick_context_dialog_delete_script))) {
                    showConfirmDeleteDialog(itemPosition);
                } else if (clickedItemText.equals(context.getText(R.string.brick_context_dialog_animate_bricks))) {
                    int itemPosition = calculateItemPositionAndTouchPointY(view);
                    Brick brick = brickList.get(itemPosition);
                    if (brick instanceof NestingBrick) {
                        List<NestingBrick> list = ((NestingBrick) brick).getAllNestingBrickParts(true);
                        for (Brick tempBrick : list) {
                            animatedBricks.add(tempBrick);
                        }
                    }
                    notifyDataSetChanged();
                } else if (clickedItemText
                        .equals(context.getText(R.string.brick_context_dialog_formula_edit_brick))) {

                    if (brickList.get(itemPosition) instanceof FormulaBrick) {
                        FormulaEditorFragment.showFragment(view, brickList.get(itemPosition),
                                ((FormulaBrick) brickList.get(itemPosition)).getFormula());
                    }
                } else if (clickedItemText
                        .equals(context.getText(R.string.brick_context_dialog_edit_script_name))) {
                    ScriptNameDialog dialog2 = new ScriptNameDialog(
                            ProjectManager.getInstance().getCurrentScript());
                    dialog2.show(((FragmentActivity) view.getContext()).getSupportFragmentManager(),
                            ScriptNameDialog.DIALOG_FRAGMENT_TAG);
                    initBrickList();
                    notifyDataSetChanged();
                    notifyDataSetInvalidated();
                }
            }
        });
        AlertDialog alertDialog = builder.create();

        if ((selectMode == ListView.CHOICE_MODE_NONE)) {
            alertDialog.show();
        }
    }

    protected void copyBrickListAndProject(int itemPosition) {
        Brick origin = (Brick) (dragAndDropListView.getItemAtPosition(itemPosition));
        Brick copy = origin.clone();

        addNewBrick(itemPosition, copy, true);

        notifyDataSetChanged();
    }

    private void showConfirmDeleteDialog(int itemPosition) {
        this.clickItemPosition = itemPosition;
        int titleId;

        if (getItem(clickItemPosition) instanceof ScriptBrick) {
            titleId = R.string.dialog_confirm_delete_script_title;
        } else {
            titleId = R.string.dialog_confirm_delete_brick_title;
        }

        AlertDialog.Builder builder = new CustomAlertDialogBuilder(context);
        builder.setTitle(titleId);
        builder.setMessage(R.string.dialog_confirm_delete_brick_message);
        builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                if (getItem(clickItemPosition) instanceof ScriptBrick) {
                    scriptToDelete = ((ScriptBrick) getItem(clickItemPosition))
                            .initScript(ProjectManager.getInstance().getCurrentSprite());
                    handleScriptDelete(sprite, scriptToDelete);
                    scriptToDelete = null;
                } else {
                    removeFromBrickListAndProject(clickItemPosition, false);
                }
            }
        });
        builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        });
        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                scriptToDelete = null;
            }
        });

        AlertDialog alertDialog = builder.create();
        alertDialog.show();
    }

    private int calculateItemPositionAndTouchPointY(View view) {
        return dragAndDropListView.pointToPosition(view.getLeft(), view.getTop());
    }

    @Override
    public void setShowDetails(boolean showDetails) {
        this.showDetails = showDetails;
    }

    @Override
    public boolean getShowDetails() {
        return showDetails;
    }

    @Override
    public void setSelectMode(int mode) {
        selectMode = mode;
    }

    @Override
    public int getSelectMode() {
        return selectMode;
    }

    @Override
    public int getAmountOfCheckedItems() {
        return getCheckedBricks().size();
    }

    @Override
    public Set<Integer> getCheckedItems() {
        return null;
    }

    @Override
    public void clearCheckedItems() {
        checkedBricks.clear();
        setCheckboxVisibility(View.GONE);
        uncheckAllItems();
        enableAllBricks();
        notifyDataSetChanged();
    }

    private void uncheckAllItems() {
        for (Brick brick : brickList) {
            CheckBox checkbox = brick.getCheckBox();
            if (checkbox != null) {
                checkbox.setChecked(false);
            }
        }
    }

    public void checkAllItems() {
        for (Brick brick : brickList) {
            if (brick instanceof ScriptBrick) {
                if (brick.getCheckBox() != null) {
                    brick.getCheckBox().setChecked(true);
                    brick.setCheckedBoolean(true);
                }
                smartBrickSelection(brick, true);
            }
        }
    }

    public void setCheckboxVisibility(int visibility) {
        for (Brick brick : brickList) {
            brick.setCheckboxVisibility(visibility);
        }
    }

    public interface OnBrickCheckedListener {
        void onBrickChecked();
    }

    public void setOnBrickCheckedListener(OnBrickCheckedListener listener) {
        onBrickCheckedListener = listener;
    }

    public void handleCheck(Brick brick, boolean isChecked) {
        if (brick == null) {
            return;
        }
        if (isChecked) {
            if (selectMode == ListView.CHOICE_MODE_SINGLE) {
                clearCheckedItems();
            }
            if (brick.getCheckBox() != null && smartBrickSelection(brick, isChecked)) {
                return;
            }
            addElementToCheckedBricks(brick);
        } else {
            if (brick.getCheckBox() != null && smartBrickSelection(brick, isChecked)) {
                return;
            }
            checkedBricks.remove(brick);
        }
        notifyDataSetChanged();

        if (onBrickCheckedListener != null) {
            onBrickCheckedListener.onBrickChecked();
        }
    }

    private void handleBrickEnabledState(Brick brick, boolean enableState) {
        if (brick.getCheckBox() != null) {
            brick.getCheckBox().setEnabled(enableState);
        }
        if (enableState) {
            brick.getViewWithAlpha(ALPHA_FULL);
        } else {
            brick.getViewWithAlpha(ALPHA_GREYED);
        }
        notifyDataSetChanged();
    }

    private void enableAllBricks() {
        for (Brick brick : brickList) {
            if (brick.getCheckBox() != null) {
                brick.getCheckBox().setEnabled(true);
            }
            brick.getViewWithAlpha(ALPHA_FULL);
        }
        notifyDataSetChanged();
    }

    private boolean smartBrickSelection(Brick brick, boolean checked) {

        if (brick instanceof ScriptBrick) {

            if (checked) {
                addElementToCheckedBricks(brick);
                animatedBricks.add(brick);
            } else {
                checkedBricks.remove(brick);
            }

            int brickPosition = brickList.indexOf(brick) + 1;
            while ((brickPosition < brickList.size()) && !(brickList.get(brickPosition) instanceof ScriptBrick)) {
                Brick currentBrick = brickList.get(brickPosition);
                if (currentBrick == null) {
                    break;
                }
                if (checked) {
                    addElementToCheckedBricks(currentBrick);
                    animatedBricks.add(currentBrick);
                } else {
                    checkedBricks.remove(currentBrick);
                }
                if (currentBrick.getCheckBox() != null) {
                    currentBrick.getCheckBox().setChecked(checked);
                    currentBrick.setCheckedBoolean(checked);
                }
                handleBrickEnabledState(currentBrick, !checked);
                brickPosition++;
            }

            animateSelectedBricks();

            if (onBrickCheckedListener != null) {
                onBrickCheckedListener.onBrickChecked();
            }
            notifyDataSetChanged();
            return true;
        } else if (brick instanceof NestingBrick) {
            for (Brick currentBrick : ((NestingBrick) brick).getAllNestingBrickParts(true)) {
                if (currentBrick == null) {
                    break;
                }
                if (checked) {
                    animatedBricks.add(currentBrick);
                    addElementToCheckedBricks(currentBrick);
                } else {
                    checkedBricks.remove(currentBrick);
                }

                currentBrick.getCheckBox().setChecked(checked);
            }

            animateSelectedBricks();

            if (onBrickCheckedListener != null) {
                onBrickCheckedListener.onBrickChecked();
            }
            notifyDataSetChanged();
            return true;
        }
        return false;
    }

    private void animateSelectedBricks() {
        if (!animatedBricks.isEmpty()) {

            for (final Brick animationBrick : animatedBricks) {
                Animation animation = AnimationUtils.loadAnimation(context, R.anim.blink);

                animation.setAnimationListener(new AnimationListener() {

                    @Override
                    public void onAnimationStart(Animation animation) {
                        animationBrick.setAnimationState(true);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        animationBrick.setAnimationState(false);
                    }
                });
                int position = animatedBricks.indexOf(animationBrick);
                animationBrick.setAnimationState(true);
                View view = animationBrick.getView(context, position, this);

                if (view.hasWindowFocus()) {
                    view.startAnimation(animation);
                }
            }

        }
        animatedBricks.clear();
    }

    private void addElementToCheckedBricks(Brick brick) {
        if (!(checkedBricks.contains(brick))) {
            checkedBricks.add(brick);
        }
    }

    public void handleScriptDelete(Sprite spriteToEdit, Script scriptToDelete) {
        spriteToEdit.removeScript(scriptToDelete);
        if (spriteToEdit.getNumberOfScripts() == 0) {
            ProjectManager.getInstance().setCurrentScript(null);
            updateProjectBrickList();
        } else {
            int lastScriptIndex = spriteToEdit.getNumberOfScripts() - 1;
            Script lastScript = spriteToEdit.getScript(lastScriptIndex);
            ProjectManager.getInstance().setCurrentScript(lastScript);
            updateProjectBrickList();
        }
    }

    public List<Brick> getCheckedBricks() {
        return checkedBricks;
    }

    public List<Brick> getCheckedBricksFromScriptBrick(ScriptBrick brick) {
        int brickPosition = checkedBricks.indexOf(brick);
        if (brickPosition >= 0) {
            List<Brick> checkedBricksInScript = new ArrayList<Brick>();
            while ((brickPosition < brickList.size()) && !(brickList.get(brickPosition) instanceof ScriptBrick)) {
                checkedBricksInScript.add(brickList.get(brickPosition));
                brickPosition++;
            }
            return checkedBricksInScript;
        }
        return null;
    }

    public List<Brick> getReversedCheckedBrickList() {
        List<Brick> reverseCheckedList = new ArrayList<Brick>();
        for (int counter = checkedBricks.size() - 1; counter >= 0; counter--) {
            reverseCheckedList.add(checkedBricks.get(counter));
        }
        return reverseCheckedList;
    }
}