/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
package org.apache.weex.ui.component.list;

import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import org.apache.weex.WXSDKInstance;
import org.apache.weex.annotation.Component;
import org.apache.weex.common.Constants;
import org.apache.weex.dom.WXAttr;
import org.apache.weex.performance.WXInstanceApm;
import org.apache.weex.ui.ComponentCreator;
import org.apache.weex.ui.action.BasicComponentData;
import org.apache.weex.ui.component.WXComponent;
import org.apache.weex.ui.component.WXHeader;
import org.apache.weex.ui.component.WXVContainer;
import org.apache.weex.ui.flat.WidgetContainer;
import org.apache.weex.ui.view.WXFrameLayout;
import org.apache.weex.utils.WXLogUtils;
import org.apache.weex.utils.WXUtils;
import org.apache.weex.utils.WXViewUtils;
import org.apache.weex.common.Constants.Name;

import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;

/**
 * Root component for components in {@link WXListComponent}
 */
@Component(lazyload = false)

public class WXCell extends WidgetContainer<WXFrameLayout> {

    private int mLastLocationY = 0;
    private ViewGroup mRealView;
    private View mTempStickyView;
    private View mHeadView;

    /** used in list sticky detect **/
    private int mScrollPosition = -1;
    private boolean mFlatUIEnabled = false;


    private Object  renderData;

    private boolean isSourceUsed = false;

    private boolean isAppendTreeDone;

    private CellAppendTreeListener cellAppendTreeListener;

    public static class Creator implements ComponentCreator {
        public WXComponent createInstance(WXSDKInstance instance,
                                          WXVContainer parent,
                                          BasicComponentData basicComponentData)
                throws IllegalAccessException, InvocationTargetException, InstantiationException {
            return new WXCell(instance, parent, true, basicComponentData);
        }
    }

    @Deprecated
    public WXCell(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) {
        super(instance, parent, basicComponentData);
    }

    public WXCell(WXSDKInstance instance, WXVContainer parent, boolean isLazy, BasicComponentData basicComponentData) {
        super(instance, parent, basicComponentData);
        lazy(true);
        if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP) {
            try {
                //TODO a WTF is necessary if anyone try to change the flat flag during update attrs.
                WXAttr attr = getAttrs();
                if (attr.containsKey(Constants.Name.FLAT)) {
                    mFlatUIEnabled = WXUtils.getBoolean(attr.get(Constants.Name.FLAT), false);
                }
            } catch (NullPointerException e) {
                WXLogUtils.e("Cell", WXLogUtils.getStackTrace(e));
            }
        }
        if (!canRecycled()){
            instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM,1);
        }
        if (TextUtils.isEmpty(getAttrs().getScope())){
            instance.getApmForInstance().updateDiffStats(WXInstanceApm.KEY_PAGE_STATS_CELL_UN_RE_USE_NUM,1);
        }
    }

    @Override
    public boolean isLazy() {
        return super.isLazy() && !isFixed();
    }

    @Override
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    public boolean isFlatUIEnabled() {
        return mFlatUIEnabled;
    }

    /**
     * If Cell is Sticky, need wraped FrameLayout
     */
    @Override
    protected WXFrameLayout initComponentHostView(@NonNull Context context) {
        if (isSticky() || this instanceof WXHeader) {
            WXFrameLayout view = new WXFrameLayout(context);
            mRealView = new WXFrameLayout(context);
            view.addView(mRealView);
            //TODO Maybe there is a better solution for hardware-acceleration view's display list.
            if (isFlatUIEnabled()) {
                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
            }
            return view;
        } else {
            WXFrameLayout view = new WXFrameLayout(context);
            mRealView = view;
            if (isFlatUIEnabled()) {
                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
            }
            return view;
        }
    }

    public int getLocationFromStart(){
        return mLastLocationY;
    }

    public void setLocationFromStart(int l){
        mLastLocationY = l;
    }

    void setScrollPositon(int pos){
        mScrollPosition = pos;
    }

    public int getScrollPositon() {
        return mScrollPosition;
    }

    @Override
    public ViewGroup getRealView() {
        return mRealView;
    }

    public void removeSticky() {
        if(getHostView().getChildCount() > 0) {
            mHeadView = getHostView().getChildAt(0);
            int[] location = new int[2];
            int[] parentLocation = new int[2];
            getHostView().getLocationOnScreen(location);
            getParentScroller().getView().getLocationOnScreen(parentLocation);
            int headerViewOffsetX = location[0] - parentLocation[0];
            int headerViewOffsetY = getParent().getHostView().getTop();
            getHostView().removeView(mHeadView);
            mRealView = (ViewGroup) mHeadView;
            mTempStickyView = new FrameLayout(getContext());
            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) getLayoutWidth(),
                    (int) getLayoutHeight());
            getHostView().addView(mTempStickyView, lp);
            mHeadView.setTranslationX(headerViewOffsetX);
            mHeadView.setTranslationY(headerViewOffsetY);
        }
    }

    public void recoverySticky() {
        if(mHeadView != null){
            if(mHeadView.getLayoutParams() != null){
                ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mHeadView.getLayoutParams();
                if(params.topMargin > 0){
                    params.topMargin = 0;
                }
            }
            if(mHeadView.getVisibility() != View.VISIBLE){
                mHeadView.setVisibility(View.VISIBLE);
            }
            if(mHeadView.getParent() != null){
                ((ViewGroup)mHeadView.getParent()).removeView(mHeadView);
            }
            getHostView().removeView(mTempStickyView);
            getHostView().addView(mHeadView);
            mHeadView.setTranslationX(0);
            mHeadView.setTranslationY(0);
        }
    }

    @Override
    protected void mountFlatGUI() {
        if(getHostView()!=null) {
            if(widgets == null){
                widgets = new LinkedList<>();
            }
            getHostView().mountFlatGUI(widgets);
        }
    }

    @Override
    public void unmountFlatGUI() {
        if (getHostView() != null) {
            getHostView().unmountFlatGUI();
        }
    }

    @Override
    public boolean intendToBeFlatContainer() {
        return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXCell.class.equals(getClass()) && !isSticky();
    }

    public int getStickyOffset(){
        if(getAttrs().get(Name.STICKY_OFFSET) == null){
            return 0;
        }
        float  offset = WXUtils.getFloat(getAttrs().get(Name.STICKY_OFFSET));
        return (int)(WXViewUtils.getRealPxByWidth(offset, getViewPortWidth()));
    }

    public Object getRenderData() {
        return renderData;
    }

    public void setRenderData(Object renderData) {
        this.renderData = renderData;
    }

    public boolean isSourceUsed() {
        return isSourceUsed;
    }

    public void setSourceUsed(boolean sourceUsed) {
        isSourceUsed = sourceUsed;
    }


    public boolean isAppendTreeDone(){
        return isAppendTreeDone;
    }

    @Override
    public void appendTreeCreateFinish() {
        super.appendTreeCreateFinish();
        isAppendTreeDone = true;
        if(cellAppendTreeListener != null){
            cellAppendTreeListener.onAppendTreeDone();
        }
    }

    public void setCellAppendTreeListener(CellAppendTreeListener cellAppendTreeListener) {
        this.cellAppendTreeListener = cellAppendTreeListener;
        if(isAppendTreeDone){
            cellAppendTreeListener.onAppendTreeDone();
        }
    }

    public interface CellAppendTreeListener{
        public void onAppendTreeDone();
    }
}
