// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.content.browser;

import android.view.View;
import android.view.ViewTreeObserver;

import java.util.ArrayList;

/**
 * Used to register listeners that can be notified of changes to the position of a view.
 */
public class ViewPositionObserver implements PositionObserver {
    private View mView;
    // Absolute position of the container view relative to its parent window.
    private final int[] mPosition = new int[2];

    private final ArrayList<Listener> mListeners;
    private ViewTreeObserver.OnPreDrawListener mPreDrawListener;

    /**
     * @param view The view to observe.
     */
    public ViewPositionObserver(View view) {
        mView = view;
        mListeners = new ArrayList<Listener>();
        updatePosition();
        mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                updatePosition();
                return true;
            }
        };
    }

    /**
     * @return The current x position of the observed view.
     */
    @Override
    public int getPositionX() {
        // The stored position may be out-of-date. Get the real current position.
        updatePosition();
        return mPosition[0];
    }

    /**
     * @return The current y position of the observed view.
     */
    @Override
    public int getPositionY() {
        // The stored position may be out-of-date. Get the real current position.
        updatePosition();
        return mPosition[1];
    }

    /**
     * Register a listener to be called when the position of the underlying view changes.
     */
    @Override
    public void addListener(Listener listener) {
        if (mListeners.contains(listener)) return;

        if (mListeners.isEmpty()) {
            mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
            updatePosition();
        }

        mListeners.add(listener);
    }

    /**
     * Remove a previously installed listener.
     */
    @Override
    public void removeListener(Listener listener) {
        if (!mListeners.contains(listener)) return;

        mListeners.remove(listener);

        if (mListeners.isEmpty()) {
            mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
        }
    }

    private void notifyListeners() {
        for (int i = 0; i < mListeners.size(); i++) {
            mListeners.get(i).onPositionChanged(mPosition[0], mPosition[1]);
        }
    }

    private void updatePosition() {
        int previousPositionX = mPosition[0];
        int previousPositionY = mPosition[1];
        mView.getLocationInWindow(mPosition);
        if (mPosition[0] != previousPositionX || mPosition[1] != previousPositionY) {
            notifyListeners();
        }
    }
}

