package com.lyft.scoop;

import android.content.Context;
import android.content.ContextWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public final class Scoop {

    static ViewBinderFactory viewBinderFactory = new NoOpViewBinderFactory();

    private String name;
    private Scoop parent;
    private Map<String, Object> services;
    private HashMap<String, Scoop> children = new LinkedHashMap<>();
    private boolean destroyed;

    private Scoop(String name, Scoop parent, Map<String, Object> services) {
        this.name = name;
        this.parent = parent;
        this.services = services;

        if (parent != null) {
            parent.children.put(name, this);
        }
    }

    public void destroy() {
        final Set<Map.Entry<String, Scoop>> entries = this.children.entrySet();

        final Set<Map.Entry<String, Scoop>> entriesCopy = new HashSet<>(entries);
        for (Map.Entry<String, Scoop> entry : entriesCopy) {
            entry.getValue().destroy();
        }

        this.destroyed = true;

        if (parent != null) {
            parent.children.remove(this.getName());
        }
    }

    boolean isDestroyed() {
        return destroyed;
    }

    public <T> T findService(String serviceName) {
        return findService(this, serviceName);
    }

    private <T> T findService(Scoop scoop, String serviceName) {
        Object service = scoop.services.get(serviceName);

        if (service != null) {
            return (T) service;
        } else {
            if (scoop.parent != null) {
                return findService(scoop.parent, serviceName);
            }
        }

        return null;
    }

    public String getName() {
        return name;
    }

    public Scoop getParent() {
        return parent;
    }

    public Scoop findChild(String childName) {
        return children.get(childName);
    }

    public static class Builder {

        private final Scoop parent;

        private final Map<String, Object> services = new LinkedHashMap<String, Object>();
        private String name;

        public Builder(String name, Scoop scoop) {
            this.name = name;
            parent = scoop;
        }

        public Builder(String name) {
            this.name = name;
            parent = null;
        }

        public Builder service(String name, Object service) {
            services.put(name, service);

            return this;
        }

        public Scoop build() {
            return new Scoop(name, parent, services);
        }
    }

    public static void setViewBinderFactory(ViewBinderFactory factory) {
        viewBinderFactory = factory;
    }

    public static Scoop fromView(View view) {
        if (view == null) {
            return null;
        }
        return fromContext(view.getContext());
    }

    public static Scoop fromContext(Context context) {

        if (!(context instanceof HaveScoop)) {
            throw new RuntimeException("View does not implement interface: HaveScoop");
        }

        HaveScoop haveScoop = (HaveScoop) context;

        return haveScoop.getScoop();
    }

    public LayoutInflater inflater(Context context) {
        return LayoutInflater.from(context).cloneInContext(createContext(context));
    }

    public Context createContext(Context context) {
        return new ScoopContextWrapper(context, this);
    }

    public View inflate(int layoutId, ViewGroup viewGroup, boolean attachToRoot) {
        return inflater(viewGroup.getContext()).inflate(layoutId, viewGroup, attachToRoot);
    }

    protected interface HaveScoop {

        Scoop getScoop();
    }

    private static class ScoopContextWrapper extends ContextWrapper implements HaveScoop {

        private final Scoop scoop;

        public ScoopContextWrapper(Context context, Scoop scoop) {
            super(context);
            this.scoop = scoop;
        }

        public Scoop getScoop() {
            return this.scoop;
        }
    }
}

@@ -186,34 +186,8 @@
 up;%0A
-import java.util.HashMap;%0A
 impo
@@ -497,20 +497,16 @@
 private 
-Hash
 Map%3CStri

use map