package me.chyxion.tigon.model;

import java.util.Map;
import lombok.Getter;
import java.util.HashMap;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br>
 * chyxion@163.com <br>
 * Oct 12, 2016 3:57:11 PM
 */
@Getter
public class ViewModel<T>
    implements ViewModelable<T> {
    private static final long serialVersionUID = 1L;

    private T data;
    private Map<String, Object> attrs;

    public ViewModel() {
    }

    /**
     * @param data
     */
    public ViewModel(T data) {
        this.data = data;
    }
    
    /**
     * @param data
     * @param attrs
     */
    public ViewModel(T data, Map<String, Object> attrs) {
        this.data = data;
        this.attrs = attrs;
    }

    /**
     * @param name
     * @param value
     * @return
     */
    @Override
    public ViewModel<T> setAttr(String name, Object value) {
        if (attrs == null) {
            attrs = new HashMap<String, Object>();
        }
        attrs.put(name, value);
        return this;
    }

    /**
     * {@inheritDoc}
     */
	@Override
    @SuppressWarnings("unchecked")
    public <A> A getAttr(String name) {
        return attrs != null ? (A) attrs.get(name) : null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ViewModelable<T> setAttrs(Map<String, Object> attrs) {
        this.attrs = attrs;
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ViewModelable<T> setData(T data) {
        this.data = data;
        return this;
    }

    /**
     * @return map
     */
    @SuppressWarnings("unchecked")
    public Map<String, Object> toMap() {
        Map<String, Object> mapRtn = null;
        if (data != null) {
            if (data instanceof Map) {
                mapRtn = (Map<String, Object>) data;
            }
            else {
                if (data instanceof ViewModelable) {
                    mapRtn = new HashMap<String, Object>();
                    mapRtn.put("data", ((ViewModelable<?>) data).toMap());
                }
                else {
                    Object jsonData = JSON.toJSON(data);
                    if (jsonData instanceof JSONObject) {
                        mapRtn = (Map<String, Object>) jsonData;
                    }
                    else {
                        mapRtn = new HashMap<String, Object>();
                        mapRtn.put("data", jsonData);
                    }
                }
            }
            if (attrs != null && !attrs.isEmpty()) {
                mapRtn.putAll(attrs);
            }
        }
        else if (attrs != null) {
            mapRtn = attrs;
        }
        else {
            mapRtn = new HashMap<String, Object>();
        }
        return mapRtn;
    }
}
