package com.reactnativenavigation.views.sharedElementTransition;

import android.view.View;

import com.reactnativenavigation.utils.ViewUtils;
import com.reactnativenavigation.utils.ViewVisibilityChecker;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class SharedElements {
    // These need to be weak references or better yet - clear them in `onViewRemoved`
    Map<String, SharedElementTransition> toElements;
    private Map<String, SharedElementTransition> fromElements;

    public void setFromElements(Map<String, SharedElementTransition> fromElements) {
        this.fromElements.clear();
        for (String fromElementKey : fromElements.keySet()) {
            if (toElements.containsKey(fromElementKey)) {
                this.fromElements.put(fromElementKey, fromElements.get(fromElementKey));
            }
        }
    }

    public void setToElements(Map<String, SharedElementTransition> toElements) {
        this.toElements.clear();
        for (String toElementKey : toElements.keySet()) {
            if (fromElements.containsKey(toElementKey)) {
                this.toElements.put(toElementKey, toElements.get(toElementKey));
            }
        }
    }

    public Map<String, SharedElementTransition> getToElements() {
        return toElements;
    }

    SharedElementTransition getFromElement(String key) {
        return fromElements.get(key);
    }

    SharedElementTransition getToElement(String key) {
        return toElements.get(key);
    }

    public void addToElement(SharedElementTransition sharedElement, String key) {
        toElements.put(key, sharedElement);
    }

    public SharedElements() {
        toElements = new HashMap<>();
        this.fromElements = new HashMap<>();
    }

    void performWhenChildViewsAreDrawn(final Runnable onReady) {
        final AtomicInteger latch = new AtomicInteger(toElements.size());
        for (SharedElementTransition toElement : toElements.values()) {
            ViewUtils.runOnPreDraw(toElement.getSharedView(), new Runnable() {
                @Override
                public void run() {
                    if (latch.decrementAndGet() == 0) {
                        onReady.run();
                    }
                }
            });
        }
    }

    void attachChildViewsToScreen() {
        for (SharedElementTransition toElement : toElements.values()) {
            toElement.attachChildToScreen();
        }
    }

    void hideToElements() {
        for (SharedElementTransition toElement : toElements.values()) {
            toElement.hide();
        }
    }

    void showToElements(final Runnable onReady) {
        final AtomicInteger latch = new AtomicInteger(toElements.size());
        for (final SharedElementTransition toElement : toElements.values()) {
            toElement.show();
            ViewUtils.runOnPreDraw(toElement, new Runnable() {
                @Override
                public void run() {
                    if (latch.decrementAndGet() == 0) {
                        onReady.run();
                    }
                }
            });
        }
    }

    void onShowAnimationEnd() {
        for (SharedElementTransition toElement : toElements.values()) {
            toElement.attachChildToSelf();
        }
    }

    void hideFromElements() {
        for (final SharedElementTransition fromElement : fromElements.values()) {
            fromElement.post(new Runnable() {
                @Override
                public void run() {
                    fromElement.setVisibility(View.INVISIBLE);
                }
            });
        }
    }

    void showToElements() {
        for (SharedElementTransition toElement : toElements.values()) {
            toElement.setVisibility(View.VISIBLE);
        }
    }

    void onHideAnimationStart() {
        for (SharedElementTransition fromElement : fromElements.values()) {
            fromElement.attachChildToScreen();
            fromElement.getSharedView().setAlpha(1);
        }
    }

    public void destroy() {
        toElements.clear();
        fromElements.clear();
    }

    public void removeHiddenElements() {
        Iterator<String> iterator = toElements.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if (!ViewVisibilityChecker.check(toElements.get(key))) {
                iterator.remove();
                fromElements.get(key).show();
            }
        }
    }
}
