func (c *Context) GetInt(key string) (int, error) {
	return strconv.Atoi(c.GetString(key))
}
GetInt gets a int value from the current request  based on the key
param:
key is key name
def default value
package bast
import (
	"bufio"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"github.com/axfor/bast/conf"
	"github.com/axfor/bast/guid"
	"github.com/axfor/bast/lang"
	"github.com/axfor/bast/logs"
	"github.com/axfor/bast/session/engine"
	"github.com/axfor/bast/validate"
	"github.com/julienschmidt/httprouter"
	"gopkg.in/yaml.v2"
)
const (
	SerError                = 0        
	SerOK                   = 1        
	SerDBError              = -10000   
	SerNoDataError          = -20000   
	SerSignOutError         = -30000   
	SerUserNotExistError    = -40000   
	SerInvalidParamError    = -50000   
	SerInvalidUserAuthorize = -60000   
	SerExist                = -70000   
	SerNotExist             = -80000   
	SerTry                  = -99999   
	SerMustFailed           = -111111  
	SerFailed               = -222222  
	SerAuthorizationFailed  = -888888  
	KindAcceptJSON          = 0        
	KindAcceptXML           = 1        
	KindAcceptYAML          = 2        
)
var valid = validate.Validator{}
type Context struct {
	In *http.Request
	Accept string
	KindAccept int
	Out http.ResponseWriter
	Params httprouter.Params
	isParseForm bool
	NeedAuthorization bool
	IsAuthorization bool
	Session engine.Store
	Router *Pattern
}
type Message struct {
	XMLName xml.Name `xml:"msg" json:"-" yaml:"-"`
	Code    int      `json:"code" xml:"code" yaml:"code"`
	Msg     string   `json:"msg" xml:"msg" yaml:"msg"`
}
type MessageDetail struct {
	XMLName xml.Name `xml:"msg" json:"-" yaml:"-"`
	Code    int      `json:"code" xml:"code" yaml:"code"`
	Msg     string   `json:"msg" xml:"msg" yaml:"msg"`
	Detail  string   `json:"detail" xml:"detail" yaml:"detail"`
}
type Datum struct {
	Message `yaml:",inline"`
	XMLName xml.Name    `xml:"data"  json:"-" yaml:"-"`
	Data    interface{} `json:"data" xml:"data>data" yaml:"data"`
}
type Pagination struct {
	Message `yaml:",inline"`
	XMLName xml.Name    `xml:"page" json:"-" yaml:"-"`
	Data    interface{} `json:"data" xml:"data>data" yaml:"data"`
	Page    int         `json:"page" xml:"page" yaml:"page"`
	Total   int         `json:"total" xml:"total" yaml:"total"`
}
type InvalidPagination struct {
	Pagination `yaml:",inline"`
	XMLName    xml.Name `xml:"page" json:"-" yaml:"-"`
	Invalid    bool     `json:"invalid" xml:"invalid" yaml:"invalid"`
	Fix        bool     `json:"fix" xml:"fix" yaml:"fix"`
}
func (c *Context) Data(v interface{}) {
	c.DataWithCodeMsg(v, SerOK, "")
}
func (c *Context) DataWithCode(v interface{}, code int) {
	c.DataWithCodeMsg(v, code, "")
}
func (c *Context) DataWithMsg(v interface{}, msg string) {
	c.DataWithCodeMsg(v, SerOK, msg)
}
func (c *Context) DataWithCodeMsg(v interface{}, code int, msg string) {
	c.DataResult(c.ObjWithCodeMsg(v, code, msg))
}
func (c *Context) DataResult(v interface{}) {
	switch c.KindAccept {
	case KindAcceptJSON:
		c.JSONResult(v)
		break
	case KindAcceptXML:
		c.XMLResult(v)
		break
	case KindAcceptYAML:
		c.YAMLResult(v)
		break
	}
}
func (c *Context) Page(v interface{}, page, total int) {
	c.PageWithCodeMsg(v, page, total, SerOK, "")
}
func (c *Context) PageWithCode(v interface{}, page, total, code int) {
	c.PageWithCodeMsg(v, page, total, code, "")
}
func (c *Context) PageWithCodeMsg(v interface{}, page, total, code int, msg string) {
	c.DataResult(c.ObjWithPageCodeMsg(v, page, total, code, msg))
}
func (c *Context) JSON(v interface{}) {
	c.JSONWithCodeMsg(v, SerOK, "")
}
func (c *Context) JSONWithCode(v interface{}, code int) {
	c.JSONWithCodeMsg(v, code, "")
}
func (c *Context) JSONWithMsg(v interface{}, msg string) {
	c.JSONWithCodeMsg(v, SerOK, msg)
}
func (c *Context) JSONWithCodeMsg(v interface{}, code int, msg string) {
	c.JSONResult(c.ObjWithCodeMsg(v, code, msg))
}
func (c *Context) JSONWithPage(v interface{}, page, total int) {
	c.JSONWithPageCodeMsg(v, page, total, SerOK, "")
}
func (c *Context) JSONWithPageCode(v interface{}, page, total, code int) {
	c.JSONWithPageCodeMsg(v, page, total, code, "")
}
func (c *Context) JSONWithPageCodeMsg(v interface{}, page, total, code int, msg string) {
	c.JSONResult(c.ObjWithPageCodeMsg(v, page, total, code, msg))
}
func (c *Context) JSONResult(v interface{}) {
	data, err := json.Marshal(v)
	if err != nil {
		logs.Errors("JSONResult error", err)
		c.StatusCode(http.StatusInternalServerError)
		return
	}
	c.Out.Header().Set("Content-Type", "application/json")
	c.Out.Write(data)
	data = nil
}
func (c *Context) XML(v interface{}) {
	c.XMLWithCodeMsg(v, SerOK, "")
}
func (c *Context) XMLWithCode(v interface{}, code int) {
	c.XMLWithCodeMsg(v, code, "")
}
func (c *Context) XMLWithMsg(v interface{}, msg string) {
	c.XMLWithCodeMsg(v, SerOK, msg)
}
func (c *Context) XMLWithCodeMsg(v interface{}, code int, msg string) {
	c.XMLResult(c.ObjWithCodeMsg(v, code, msg))
}
func (c *Context) XMLWithPage(v interface{}, page, total int) {
	c.XMLWithPageCodeMsg(v, page, total, SerOK, "")
}
func (c *Context) XMLWithPageCode(v interface{}, page, total, code int) {
	c.XMLWithPageCodeMsg(v, page, total, code, "")
}
func (c *Context) XMLWithPageCodeMsg(v interface{}, page, total, code int, msg string) {
	c.XMLResult(c.ObjWithPageCodeMsg(v, page, total, code, msg))
}
func (c *Context) XMLResult(v interface{}) {
	data, err := xml.Marshal(v)
	if err != nil {
		logs.Errors("XMLResult error", err)
		c.StatusCode(http.StatusInternalServerError)
		return
	}
	c.Out.Header().Set("Content-Type", "application/xml")
	c.Out.Write(data)
	data = nil
}
func (c *Context) YAML(v interface{}) {
	c.YAMLWithCodeMsg(v, SerOK, "")
}
func (c *Context) YAMLWithCode(v interface{}, code int) {
	c.YAMLWithCodeMsg(v, code, "")
}
func (c *Context) YAMLWithMsg(v interface{}, msg string) {
	c.YAMLWithCodeMsg(v, SerOK, msg)
}
func (c *Context) YAMLWithCodeMsg(v interface{}, code int, msg string) {
	c.YAMLResult(c.ObjWithCodeMsg(v, code, msg))
}
func (c *Context) YAMLWithPage(v interface{}, page, total int) {
	c.YAMLWithPageCodeMsg(v, page, total, SerOK, "")
}
func (c *Context) YAMLWithPageCode(v interface{}, page, total, code int) {
	c.YAMLWithPageCodeMsg(v, page, total, code, "")
}
func (c *Context) YAMLWithPageCodeMsg(v interface{}, page, total, code int, msg string) {
	c.YAMLResult(c.ObjWithPageCodeMsg(v, page, total, code, msg))
}
func (c *Context) YAMLResult(v interface{}) {
	data, err := yaml.Marshal(v)
	if err != nil {
		logs.Errors("YAMLResult error", err)
		c.StatusCode(http.StatusInternalServerError)
		return
	}
	c.Out.Header().Set("Content-Type", "application/x+yaml")
	c.Out.Write(data)
	data = nil
}
func (c *Context) ObjWithCodeMsg(v interface{}, code int, msg string) interface{} {
	if !app.wrap {
		return v
	}
	if isDatumType(v) || isPaginationType(v) || isInvalidPaginationType(v) || isMessageType(v) || isMessageDetailType(v) {
		return v
	}
	d := &Datum{}
	d.Code = code
	d.Msg = msg
	d.Data = v
	return d
}
func isDatumType(v interface{}) bool {
	_, ok := v.(*Datum)
	return ok
}
func isPaginationType(v interface{}) bool {
	_, ok := v.(*Pagination)
	return ok
}
func isInvalidPaginationType(v interface{}) bool {
	_, ok := v.(*InvalidPagination)
	return ok
}
func isMessageType(v interface{}) bool {
	_, ok := v.(*Message)
	return ok
}
func isMessageDetailType(v interface{}) bool {
	_, ok := v.(*MessageDetail)
	return ok
}
func (c *Context) ObjWithPageCodeMsg(v interface{}, page, total, code int, msg string) interface{} {
	if !app.wrap {
		return v
	}
	d := &InvalidPagination{}
	_, _total, pageRow := c.GetPage()
	if _total == 0 {
		last := int(math.Ceil(float64(total) / float64(pageRow)))
		if page >= last {
			page = last - 1
			d.Fix = true
		}
	}
	page++
	if v != nil {
		switch reflect.TypeOf(v).Kind() {
		case reflect.Array:
		case reflect.Map:
		case reflect.Slice:
			s := reflect.ValueOf(v)
			if s.Len() == 0 {
				d.Invalid = true
			}
			break
		}
	} else {
		d.Invalid = true
	}
	d.Data = v
	d.Page = page
	d.Total = total
	d.Code = code
	d.Msg = msg
	if d.Invalid || d.Fix {
		return d
	}
	return d.Pagination
}
func (c *Context) Pusher() http.Pusher {
	if per, ok := c.Out.(http.Pusher); ok {
		return per
	}
	return nil
}
func (c *Context) Flush() {
	if puser, ok := c.Out.(http.Flusher); ok {
		puser.Flush()
	}
}
func (c *Context) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if hijer, ok := c.Out.(http.Hijacker); ok {
		return hijer.Hijack()
	}
	return nil, nil, errors.New("not support http hijacker")
}
func (c *Context) Success(msg string) {
	v := &Message{}
	v.Code = SerOK
	v.Msg = msg
	c.Data(v)
}
func (c *Context) Successf(format string, a ...interface{}) {
	if a != nil && len(a) > 0 {
		format = fmt.Sprintf(format, a...)
	}
	v := &Message{}
	v.Code = SerOK
	v.Msg = format
	c.Data(v)
}
func (c *Context) Failed(msg string, err ...error) {
	c.FailResult(msg, SerError, err...)
}
func (c *Context) Faileds(msg string, detail string) {
	v := &MessageDetail{}
	v.Code = SerError
	v.Msg = msg
	v.Detail = detail
	c.DataWithCode(v, SerError)
}
func (c *Context) Failedf(format string, a ...interface{}) {
	var err error
	if a != nil {
		lg := len(a)
		if lg > 0 {
			if a[lg-1] != nil {
				err, _ = a[lg-1].(error)
			}
			if err != nil {
				a = a[0 : lg-1]
			}
			if len(a) > 0 {
				format = fmt.Sprintf(format, a...)
			}
		}
	}
	c.FailResult(format, SerError, err)
}
func (c *Context) Result(msg string, detail ...string) {
	v := &MessageDetail{}
	v.Code = SerOK
	v.Msg = msg
	if detail != nil {
		for _, s := range detail {
			if v.Detail != "" {
				v.Detail += ","
			}
			v.Detail += s
		}
	}
	c.DataWithCode(v, SerError)
	v = nil
}
func (c *Context) FailResult(msg string, errCode int, err ...error) {
	v := &Message{}
	if errCode == 0 {
		errCode = SerError
	}
	v.Code = errCode
	v.Msg = msg
	if err != nil && err[0] != nil {
		v.Msg += ", [" + err[0].Error() + "]"
	}
	c.DataWithCode(v, errCode)
}
func (c *Context) SignOut(msg string) {
	c.FailResult(msg, SerSignOutError)
}
func (c *Context) NoData(msg string) {
	c.FailResult(msg, SerNoDataError)
}
func (c *Context) Say(data []byte) {
	c.Out.Write(data)
}
func (c *Context) Says(str string) {
	c.Out.Write([]byte(str))
}
func (c *Context) SendFile(fileName string, rawFileName ...string) {
	dir := filepath.Dir(fileName)
	fileName = filepath.Base(fileName)
	url := c.BaseURL("f/" + fileName)
	fileName = "/f/" + fileName
	fs := http.StripPrefix("/f/", http.FileServer(http.Dir(dir)))
	r, _ := http.NewRequest("GET", url, nil)
	raw := fileName
	if rawFileName != nil {
		raw = rawFileName[0]
		c.Out.Header().Set("Content-Disposition", "attachment; filename="+raw)
	}
	fs.ServeHTTP(c.Out, r)
	r = nil
	fs = nil
}
func (c *Context) JSON2String(obj interface{}) (string, error) {
	data, err := json.Marshal(obj)
	if err != nil {
		return "", nil
	}
	return string(data), err
}
func (c *Context) String2JSON(str string, obj interface{}) error {
	return c.JSONDecode(strings.NewReader(str), obj)
}
func (c *Context) Verify(rules ...string) error {
	return c.Validate(rules...)
}
func (c *Context) Validate(rules ...string) error {
	c.In.ParseForm()
	return valid.Request(c.In.Form, rules...)
}
func (c *Context) StatusCode(statusCode int) {
	c.Out.WriteHeader(statusCode)
	c.Out.Write([]byte(http.StatusText(statusCode)))
}
func (c *Context) RawString() string {
	body, err := ioutil.ReadAll(c.In.Body)
	if err != nil {
		return ""
	}
	return string(body)
}
func (c *Context) GetString(key string) string {
	d := c.GetStrings(key)
	if len(d) > 0 {
		return d[0]
	}
	return ""
}
func (c *Context) GetStringValue(key string, def string) string {
	d := c.GetString(key)
	if d != "" {
		return d
	}
	return def
}
func (c *Context) GetTrimString(key string) string {
	return strings.TrimSpace(c.GetString(key))
}
func (c *Context) GetStringSlice(key, sep string) []string {
	s := c.GetTrimString(key)
	if len(s) > 0 {
		ss := strings.Split(s, sep)
		if len(ss) > 0 {
			return ss
		}
	}
	return nil
}
func (c *Context) GetIntSlice(key, sep string) []int64 {
	s := c.GetTrimString(key)
	if len(s) > 0 {
		ss := strings.Split(s, sep)
		lg := len(ss)
		si := make([]int64, lg, lg)
		for i := 0; i < lg; i++ {
			si[i], _ = strconv.ParseInt(ss[i], 10, 64)
		}
		if len(si) > 0 {
			return si
		}
	}
	return nil
}
func (c *Context) GetIntSliceAndRemovePrefix(key, sep, prefix string) ([]int64, bool) {
	s := c.GetTrimString(key)
	has := false
	if len(s) > 0 {
		if prefix != "" {
			has = strings.HasPrefix(s, prefix)
			s = strings.TrimPrefix(s, prefix)
		}
		ss := strings.Split(s, sep)
		lg := len(ss)
		si := make([]int64, 0, lg)
		for i := 0; i < lg; i++ {
			n, err := strconv.ParseInt(ss[i], 10, 64)
			if err == nil {
				si = append(si, n)
			}
		}
		if len(si) > 0 {
			return si, has
		}
	}
	return nil, false
}
func (c *Context) GetParam(key string) string {
	return c.Params.ByName(key)
}
func (c *Context) GetLeftLikeString(key string) string {
	d := c.GetStrings(key)
	if len(d) > 0 {
		r := d[0]
		if r != "" {
			return r + "%"
		}
	}
	return ""
}
func (c *Context) GetRightLikeString(key string) string {
	d := c.GetStrings(key)
	if len(d) > 0 {
		r := d[0]
		if r != "" {
			return "%" + r
		}
	}
	return ""
}
func (c *Context) GetLikeString(key string) string {
	d := c.GetStrings(key)
	if len(d) > 0 {
		r := d[0]
		if r != "" {
			return "%" + r + "%"
		}
	}
	return ""
}
func (c *Context) GetBool(key string) bool {
	d := c.GetStrings(key)
	if len(d) > 0 {
		ok, err := strconv.ParseBool(d[0])
		if err == nil {
			return ok
		}
	}
	return false
}
func (c *Context) GetBoolValue(key string, def bool) bool {
	d := c.GetStrings(key)
	if len(d) > 0 {
		ok, err := strconv.ParseBool(d[0])
		if err == nil {
			return ok
		}
	}
	return def
}
func (c *Context) GetStrings(key string) []string {
	c.ParseForm()
	return c.In.Form[key]
}