/**
 * Created by rburson on 3/18/16.
 */
import * as React from 'react'
import {
    CvAction,
    CvState,
    CvProps,
    CvBaseMixin,
    CvListPane,
    CvRecordList,
    CvNavigationResult,
    CvEvent,
    CvRecord,
    CvContext,
    CvQueryPaneCallback,
    CvValueListener,
    CvValueAdapter,
    CvStateChangeResult,
    CvActionFiredResult,
    CvActionCallback,
    CvValueProvider,
    CvActionHandlerParams,
    CvNavigation,
    CvForm,
    CvSearchPane,
    CvSearchPaneCallback,
    CvSortDirection
} from 'catreact'
import {
    CvDataAnno,
    CvDataAnnoStyle,
    CvHtmlProp
} from './catreact-html'
import {FormContext, ListContext, Prop, ColumnDef, EntityRec} from 'catavolt-sdk'

export interface CvListPanelState extends CvState {
    selectedItems:Array<string>;
    searchNavResult:CvNavigationResult;
}

export interface CvListPanelProps extends CvProps {
    paneRef?:number;
    formContext?:FormContext;
    listContext?:ListContext;
    navigationListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>;
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>
    selectionListener?:CvValueListener<Array<string>>;
    stateChangeListeners?:Array<(event:CvEvent<CvStateChangeResult>)=>void>;
    actionProvider?:CvValueProvider<CvActionHandlerParams>;
    searchable?:boolean;
}

/*
 ***************************************************
 * Render a ListContext
 ***************************************************
 */
export var CvListPanel = React.createClass<CvListPanelProps, CvListPanelState>({

    mixins: [CvBaseMixin],

    getDefaultProps: function () {
        return {
            paneRef: null,
            formContext: null,
            listContext: null,
            navigationListeners: [],
            selectionListener: null,
            stateChangeListeners: [],
            actionProvider:null,
            searchable:false,
        }
    },

    getInitialState: function () {
        return {selectedItems: [], searchNavResult:null}
    },

    render: function () {

        /* We can't do ES7 style rest destructuring in Typescript yet... */
        const listPaneProps = {
            paneRef: this.props.paneRef,
            formContext: this.props.formContext,
            queryContext: this.props.listContext,
            stateChangeListeners: this.props.stateChangeListeners,
            actionListeners: this.props.actionListeners,
            actionProvider: this.props.actionProvider
        }

        return (
            <CvListPane {...listPaneProps} recordPageSize={50} queryRenderer={(cvContext:CvContext, callback:CvQueryPaneCallback)=>{
                const listContext:ListContext = cvContext.scopeCtx.scopeObj;
                return(
                    <div className="cv-list-container">
                         {(()=>{
                             return this.props.searchable ?
                                <CvAction actionId={'#search'} fireOnLoad={(success, error)=>{}} paneContext={listContext}
                                    navigationListeners={[(event:CvEvent<CvNavigationResult>)=>{
                                        this.setState({searchNavResult: event.eventObj});
                                    }]}/> : null;
                         })()}
                        <div className="text-right">
                            <button className="btn btn-default" onClick={callback.refresh}>
                                <span className="glyphicon glyphicon-refresh" aria-hidden="true"/>
                            </button>
                            {(()=>{
                                return this.props.searchable ?
                                    <CvAction actionId={'#search'}
                                        paneContext={listContext}
                                        navigationListeners={this.props.navigationListeners}
                                        actionListeners={this.props.actionListeners}
                                        stateChangeListeners={this.props.stateChangeListeners}
                                        renderer={(cvContext:CvContext, callback?:CvActionCallback)=>{
                                            return <button className="btn btn-default" onClick={()=>{callback.fireAction()}}>
                                                <span className="glyphicon glyphicon-search" aria-hidden="true"/>
                                            </button>
                                        }}/> : null;
                            })()}
                        </div>
                        <div className="cv-list-scrollpane" onScroll={this._magicScroll.bind(this, callback)}>
                            <table className="table table-striped cv-table">
                                <CvListTableHeader searchNavResult={this.state.searchNavResult} listContext={listContext}/>
                                <CvRecordList queryContext={listContext} wrapperElemName={'tbody'}
                                      rowRenderer={(cvContext, record)=>{
                                        return (
                                         <CvRecord entityRec={record} key={record.objectId} renderer={(cvContext:CvContext)=>{
                                                const rowProps  = this._isSelected(record.objectId) ? {className: 'cv-selected-row'} : {};
                                                rowProps['onClick'] = this._itemClicked.bind(this, record.objectId);
                                                return (
                                                    <CvDataAnno entityRec={record}
                                                                paneContext={listContext}
                                                                wrapperElem="tr" wrapperElemProps={rowProps}>
                                                            <td className="cv-list-cell">
                                                            </td>
                                                            {listContext.listDef.activeColumnDefs.map((columnDef:ColumnDef)=> {
                                                                const name:string = columnDef.name; 
                                                                //select "this record" so that the action can find the target via the selectionProvider
                                                                const selectionAdapter:CvValueAdapter<Array<string>> = new CvValueAdapter<Array<string>>();
                                                                selectionAdapter.createValueListener()([record.objectId]);
                                                                const prop:Prop = record.propAtName(name);
                                                                return (
                                                                    <CvAction actionId={listContext.listDef.defaultActionId}
                                                                        paneContext={listContext}
                                                                        navigationListeners={this.props.navigationListeners}
                                                                        actionListeners={this.props.actionListeners}
                                                                        stateChangeListeners={this.props.stateChangeListeners}
                                                                        selectionProvider={selectionAdapter}
                                                                        key={prop.name} renderer={(cvContext:CvContext, callback?:CvActionCallback)=>{
                                                                            const styleInfo:CvDataAnnoStyle = (CvDataAnno as any).generateStyleInfo(prop);
                                                                            const cellStyle = 'cv-list-cell cv-target ' + CvListColumnHeader.classForColumnDef(columnDef);
                                                                            return(
                                                                             <CvDataAnno dataAnnoStyle={styleInfo}
                                                                                         paneContext={listContext}
                                                                                         wrapperElem="td"
                                                                                         wrapperElemProps={{className:cellStyle}}>
                                                                                <CvHtmlProp propName={prop.name}
                                                                                    entityRec={record}
                                                                                    paneContext={listContext}
                                                                                    imageClassName="cv-image-list-item-max-size"
                                                                                    wrapperElemProps={{onClick:(e)=>{
                                                                                        e.preventDefault();
                                                                                        e.stopPropagation();
                                                                                        callback.fireAction()}
                                                                                    }}
                                                                                    overrideValue={styleInfo.overrideText}/>
                                                                             </CvDataAnno>
                                                                            );
                                                                    }}/>
                                                                )
                                                            })}
                                                    </CvDataAnno>
                                                );
                                         }}/>
                                        );
                                }}/>
                            </table>
                            {/*

                             //The following is an example of using paging controls, rather then infintite scrolling
                             //The style should be changed in the above pane, to remove the scrollbar, for this example work nicely
                             //When using the 'true' value for the replaceBuffer flag with the below paging methods, the list is updated
                             //to reflect only the current page in the buffer

                            <div className="cv-paging-controls">
                                <div>
                                {(()=>{ if(callback.hasMoreBackward()){ return (
                                    <button type="button" className="btn btn-default btn-sm" onClick={(()=>{callback.pageBackward((num)=>{}, true)})}>
                                            <span className="glyphicon glyphicon-menu-left" aria-hidden="true"/>
                                            <span>Prev</span>
                                    </button>
                                );}})()}
                                </div>
                                <div className="pull-right">
                                {(()=>{ if(callback.hasMoreForward()){ return (
                                    <button type="button" className="btn btn-default btn-sm" onClick={()=>{callback.pageForward((num)=>{}, true)}}>
                                            <span>Next</span>
                                            <span className="glyphicon glyphicon-menu-right" aria-hidden="true"/>
                                    </button>
                                );}})()}
                                </div>
                            </div>
                            */}
                        </div>
                    </div>);
            }}/>
        );
    },

    _isSelected: function (oid:string) {
        return this.state.selectedItems.indexOf(oid) > -1;
    },

    _itemClicked: function (oid:string) {
        const selectedItems:Array<string> = this.state.selectedItems;
        const index = selectedItems.indexOf(oid);
        if (index > -1) {
            selectedItems.splice(index, 1);
        } else {
            selectedItems.push(oid);
        }
        this.setState({selectedItems: selectedItems});
        if (this.props.selectionListener) this.props.selectionListener(selectedItems);
    },

    _magicScroll: function (callback:CvQueryPaneCallback, e:any) {
        var elem:any = e.currentTarget;
        if (elem.scrollTop / (elem.scrollHeight - elem.clientHeight) > .95) {
            if(callback.hasMoreForward()) {
                callback.pageForward((num)=> {
                });
            }
        }
    },
    
});

export var CvListTableHeader = React.createClass<{searchNavResult:CvNavigationResult, listContext:ListContext},{}>({

    getDefaultProps: function () {
        return {searchNavResult: null, listContext: null}
    },

    render: function () {

        const {searchNavResult, listContext} = this.props;

        return (
            <thead>
            {searchNavResult ?
                (<CvNavigation navigationResult={searchNavResult}>
                    <CvForm formContext={searchNavResult.navRequest}>
                        <CvSearchPane paneRef={0} detailsRenderer={(cvContext:CvContext,
                            entityRec:EntityRec, callback:CvSearchPaneCallback)=>{
                                return <tr>
                                    {[<th key={'select_col'} />].concat(listContext.listDef.activeColumnDefs.map((colDef, i) => {
                                        return <CvListColumnHeader colDef={colDef} searchCallback={callback} key={i}/>
                                    }))}
                                </tr>
                            }}/>
                    </CvForm>
                </CvNavigation>)
                : 
                (<tr>
                    {[<th key="select_col"/>].concat(listContext.listDef.activeColumnDefs.map((colDef, index) => {
                        return <th key={index}>{colDef.heading}</th>
                    }))}
                </tr>)
            }
        </thead>);
    }
    
});

export var CvListColumnHeader = React.createClass<{colDef:ColumnDef, searchCallback:CvSearchPaneCallback},{}>({

    getDefaultProps: function () {
        return {colDef: null, searchCallback: null}
    },

    render: function () {
       
        const {colDef, searchCallback} = this.props;
        const dir = searchCallback.getSortValueDirection(colDef.name);

        //server may return ASCENDING or ASC and DSC or DESCENDING
        const nextDir = this._isAsc(dir) ? 'DSC' : 'ASC';

        //size the cell
        let sizeClass = ' ' + CvListColumnHeader.classForColumnDef(colDef);
        return <th className={'cv-target' + sizeClass} onClick={((colName)=>{
            searchCallback.reopenSearch((success, error)=>{
                searchCallback.clearSortValues();
                searchCallback.setSortValue(colName, nextDir, 0);
                searchCallback.submitSearch((success, error)=>{});
            })
        }).bind(this, colDef.name)}>
            <span>{colDef.heading}</span>
            {(()=>{
                if(dir) {
                    const className = this._isAsc(dir) ?
                        "glyphicon glyphicon-triangle-top cv-sort-dir" : "glyphicon glyphicon-triangle-bottom cv-sort-dir";
                    return <span className={className} aria-hidden="true"/>
                } else {
                    return null;
                }
            })()}
        </th>
    },
    
    _isAsc: function(dir:string) {
        return dir && dir.indexOf('A') === 0;
    },
    
    _isDsc: function(dir:string) {
        return dir && dir.indexOf('D') === 0;
    },
    
    statics : {
        classForColumnDef:function(colDef:ColumnDef) {
            if(colDef.propertyDef.presLength > 500) {
                return 'cv-list-cell-width-xl'
            }else if(colDef.propertyDef.presLength >= 200) {
                return 'cv-list-cell-width-lg'
            }else if(colDef.propertyDef.presLength >= 100) {
                return 'cv-list-cell-width-md'
            } else {
                return 'cv-list-cell-width-default'
            }
        }
    }

});



