package com.firebase.ui.database;

/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.util.Log;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;
import java.util.List;

class FirebaseIndexArray extends FirebaseArray implements ValueEventListener {
    private static final String TAG = FirebaseIndexArray.class.getSimpleName();

    private DatabaseReference mRef;
    private List<DataSnapshot> mDataSnapshots = new ArrayList<>();
    private OnChangedListener mListener;

    FirebaseIndexArray(Query keyRef, DatabaseReference dataRef) {
        super(keyRef);
        mRef = dataRef;
    }

    @Override
    public void cleanup() {
        super.cleanup();
        for (DataSnapshot snapshot : mDataSnapshots) {
            snapshot.getRef().removeEventListener((ValueEventListener) this);
        }
    }

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

    @Override
    public DataSnapshot getItem(int index) {
        return mDataSnapshots.get(index);
    }

    private int getIndexForKey(String key) {
        int dataCount = getCount();
        int index = 0;
        for (int keyIndex = 0; index < dataCount; keyIndex++) {
            String superKey = super.getItem(keyIndex).getKey();
            if (key.equals(superKey)) {
                break;
            } else if (getItem(index).getKey().equals(superKey)) {
                index++;
            }
        }
        return index;
    }

    private boolean isMatch(int index, String key) {
        return index >= 0 && index < getCount() && getItem(index).getKey().equals(key);
    }

    @Override
    public void onChildAdded(DataSnapshot keySnapshot, String previousChildKey) {
        super.onChildAdded(keySnapshot, previousChildKey);
        mRef.child(keySnapshot.getKey()).addValueEventListener(this);
    }

    @Override
    public void onDataChange(DataSnapshot snapshot) {
        String key = snapshot.getKey();
        int index = getIndexForKey(key);

        if (snapshot.getValue() != null) {
            if (!isMatch(index, key)) {
                mDataSnapshots.add(index, snapshot);
                notify(OnChangedListener.EventType.Added, index, -1);
            } else {
                mDataSnapshots.set(index, snapshot);
                notify(OnChangedListener.EventType.Changed, index, -1);
            }
        } else {
            Log.w(TAG, "Key not found at ref: " + snapshot.getRef());
            if (isMatch(index, key)) {
                mDataSnapshots.remove(index);
                notify(OnChangedListener.EventType.Removed, index, -1);
            }
        }
    }

    @Override
    public void onChildRemoved(DataSnapshot keySnapshot) {
        String key = keySnapshot.getKey();
        int index = getIndexForKey(key);
        mRef.child(key).removeEventListener((ValueEventListener) this);
        super.onChildRemoved(keySnapshot);
        if (isMatch(index, key)) {
            mDataSnapshots.remove(index);
            notify(OnChangedListener.EventType.Removed, index, -1);
        }
    }

    @Override
    public void onChildMoved(DataSnapshot keySnapshot, String previousChildKey) {
        String key = keySnapshot.getKey();
        int oldIndex = getIndexForKey(key);
        super.onChildMoved(keySnapshot, previousChildKey);

        if (isMatch(oldIndex, key)) {
            DataSnapshot snapshot = mDataSnapshots.remove(oldIndex);
            int newIndex = getIndexForKey(key);
            mDataSnapshots.add(newIndex, snapshot);
            notify(OnChangedListener.EventType.Moved, newIndex, oldIndex);
        }
    }

    @Override
    public void setOnChangedListener(OnChangedListener listener) {
        mListener = listener;
    }

    private void notify(OnChangedListener.EventType type,
                                          int index,
                                          int oldIndex) {
        if (mListener != null) {
            mListener.onChanged(type, index, oldIndex);
        }
    }
}

@@ -2457,50 +2457,139 @@
 per.
-onChildAdded(keySnapshot, previousChildKey
+setOnChangedListener(null);%0A        super.onChildAdded(keySnapshot, previousChildKey);%0A        super.setOnChangedListener(mListener
 );%0A 
@@ -2964,32 +2964,48 @@
           notify
+ChangedListeners
 (OnChangedListen
@@ -3021,36 +3021,32 @@
 ype.Added, index
-, -1
 );%0A            %7D
@@ -3120,32 +3120,48 @@
           notify
+ChangedListeners
 (OnChangedListen
@@ -3179,36 +3179,32 @@
 e.Changed, index
-, -1
 );%0A            %7D
@@ -3390,32 +3390,48 @@
           notify
+ChangedListeners
 (OnChangedListen
@@ -3449,36 +3449,32 @@
 e.Removed, index
-, -1
 );%0A            %7D
@@ -3483,32 +3483,281 @@
        %7D%0A    %7D%0A%0A
+    @Override%0A    public void onChildChanged(DataSnapshot snapshot, String previousChildKey) %7B%0A        super.setOnChangedListener(null);%0A        super.onChildChanged(snapshot, previousChildKey);%0A        super.setOnChangedListener(mListener);%0A    %7D%0A%0A
     @Override%0A  
@@ -3960,32 +3960,75 @@
 Listener) this);
+%0A%0A        super.setOnChangedListener(null);
 %0A        super.o
@@ -4047,32 +4047,80 @@
 d(keySnapshot);%0A
+        super.setOnChangedListener(mListener);%0A%0A
         if (isMa
@@ -4190,32 +4190,48 @@
           notify
+ChangedListeners
 (OnChangedListen
@@ -4261,12 +4261,8 @@
 ndex
-, -1
 );%0A 
@@ -4451,32 +4451,75 @@
 ndexForKey(key);
+%0A%0A        super.setOnChangedListener(null);
 %0A        super.o
@@ -4557,24 +4557,71 @@
 usChildKey);
+%0A        super.setOnChangedListener(mListener);
 %0A%0A        if
@@ -4831,24 +4831,40 @@
       notify
+ChangedListeners
 (OnChangedLi
@@ -5018,205 +5018,45 @@
     
-mListener = listener;%0A    %7D%0A%0A    private void notify(OnChangedListener.EventType type,%0A                                          int index,%0A                                          int oldIndex) %7B
+super.setOnChangedListener(listener);
 %0A   
@@ -5060,20 +5060,16 @@
         
-if (
 mListene
@@ -5074,84 +5074,19 @@
 ner 
-!
 = 
-null) %7B%0A            mListener.onChanged(type, index, oldIndex);%0A        %7D
+listener;
 %0A   

Add back supers