func (receiver *BaseController) GetResourceSingleURL() (string, error) {
	resourceName, err := receiver.GetResourceName()
	if err != nil {
		logging.Logger().Debug(err.Error())
		return "", err
	}
	return fmt.Sprintf("%s/:key_parameter", resourceName), nil
}
GetResourceSingleURL builds a resource url what represents a single resource based on the argument
package controller
import (
	"strings"
	dbpkg "github.com/qb0C80aE/clay/db"
	"github.com/qb0C80aE/clay/helper"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"regexp"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/qb0C80aE/clay/extension"
	"github.com/qb0C80aE/clay/logging"
	"github.com/qb0C80aE/clay/util/conversion"
	"github.com/qb0C80aE/clay/util/mapstruct"
	"github.com/qb0C80aE/clay/version"
	validatorpkg "gopkg.in/go-playground/validator.v9"
	"gopkg.in/yaml.v2"
)
type BaseController struct {
	actualController extension.Controller
	model            extension.Model
	binder           extension.Binder
	outputHandler    extension.OutputHandler
	queryCustomizer  extension.QueryCustomizer
}
var validator = validatorpkg.New()
var intTypeString = reflect.TypeOf(int(0)).String()
var int8TypeString = reflect.TypeOf(int8(0)).String()
var int16TypeString = reflect.TypeOf(int16(0)).String()
var int32TypeString = reflect.TypeOf(int32(0)).String()
var int64TypeString = reflect.TypeOf(int64(0)).String()
var uintTypeString = reflect.TypeOf(uint(0)).String()
var uint8TypeString = reflect.TypeOf(uint8(0)).String()
var uint16TypeString = reflect.TypeOf(uint16(0)).String()
var uint32TypeString = reflect.TypeOf(uint32(0)).String()
var uint64TypeString = reflect.TypeOf(uint64(0)).String()
var float32TypeString = reflect.TypeOf(float32(0)).String()
var float64TypeString = reflect.TypeOf(float64(0)).String()
var booleanTypeString = reflect.TypeOf(true).String()
var stringTypeString = reflect.TypeOf("").String()
var bytesTypeString = reflect.TypeOf([]byte{}).String()
var stringInterfaceMapTypeString = reflect.TypeOf(map[string]interface{}{}).String()
var formKeyHashRegExp, _ = regexp.Compile("^([a-zA-Z_][a-zA-Z0-9_]*)\\[([a-zA-Z_][a-zA-Z0-9_]*)\\]$")
func getMapingTagValue(structField *reflect.StructField, tagName string) string {
	tag := structField.Name
	tagValueList := strings.Split(structField.Tag.Get(tagName), ",")
	for _, tagValue := range tagValueList {
		switch tagValue {
		case "omitempty":
			continue
		default:
			tag = tagValue
			break
		}
	}
	return tag
}
func CreateController(actualController extension.Controller, model extension.Model) extension.Controller {
	actualControllerValue := reflect.ValueOf(actualController).Elem()
	baseController := BaseController{
		actualController: actualController,
		model:            model,
		binder:           actualController.(extension.Binder),
		outputHandler:    actualController.(extension.OutputHandler),
		queryCustomizer:  actualController.(extension.QueryCustomizer),
	}
	baseControllerValue := reflect.ValueOf(baseController)
	actualControllerValue.FieldByName("BaseController").Set(baseControllerValue)
	return actualController
}
func executeValidation(c *gin.Context, resourceName string, inputContainer interface{}, keyParameterSpecifier string) error {
	model, err := extension.GetAssociatedModelWithResourceName(resourceName)
	if err != nil {
		logging.Logger().Debug(err.Error())
		return err
	}
	modelKey, err := extension.GetModelKey(model, keyParameterSpecifier)
	if err != nil {
		logging.Logger().Debug(err.Error())
		return err
	}
	keyParameterValue := c.Param(modelKey.KeyParameter)
	if len(keyParameterValue) > 0 {
		containerValue := reflect.ValueOf(inputContainer)
		for containerValue.Kind() == reflect.Ptr {
			containerValue = containerValue.Elem()
		}
		keyField := containerValue.FieldByName(modelKey.KeyField)
		switch keyField.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			v, err := strconv.Atoi(keyParameterValue)
			if err != nil {
				logging.Logger().Debug(err.Error())
				return err
			}
			keyField.SetInt(int64(v))
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			v, err := strconv.Atoi(keyParameterValue)
			if err != nil {
				logging.Logger().Debug(err.Error())
				return err
			}
			keyField.SetUint(uint64(v))
		default:
			keyField.SetString(fmt.Sprintf("%s", keyParameterValue))
		}
	}
	validator.SetTagName("validate")
	if err := validator.Struct(inputContainer); err != nil {
		logging.Logger().Debug(err.Error())
		return err
	}
	return nil
}
func (receiver *BaseController) determineResponseCharsetTypeFromAcceptCharset(c *gin.Context) string {
	acceptCharsetList := strings.Split(c.Request.Header.Get("Accept-Charset"), ",")
	switch len(acceptCharsetList) {
	case 0:
		return extension.AcceptCharsetUTF8
	default:
		firstAcceptCharset := strings.Trim(acceptCharsetList[0], " ")
		if len(firstAcceptCharset) == 0 {
			return extension.AcceptCharsetUTF8
		}
		return firstAcceptCharset
	}
}
func (receiver *BaseController) outputTextWithContentType(c *gin.Context, code int, result interface{}) {
	text := result.(string)
	acceptList := strings.Split(c.Request.Header.Get("Accept"), ",")
	accept := extension.DetermineResponseContentTypeFromAccept(acceptList)
	switch accept {
	case "", extension.AcceptAll:
		c.String(code, text)
	default:
		acceptCharset := receiver.determineResponseCharsetTypeFromAcceptCharset(c)
		var contentType string
		if len(strings.Trim(acceptCharset, " ")) > 0 {
			contentType = fmt.Sprintf("%s; charset=%s", accept, acceptCharset)
		} else {
			contentType = accept
		}
		c.Data(code, contentType, []byte(text))
	}
}
func (receiver *BaseController) Bind(c *gin.Context, resourceName string) (interface{}, error) {
	preloadedBody := c.MustGet("PreloadedBody").([]byte)
	switch c.ContentType() {
	case extension.ContentTypeJSON, extension.ContentTypeXYAML, extension.ContentTypeTextYAML:
		inputMap := map[string]interface{}{}
		var data interface{}
		switch c.ContentType() {
		case extension.ContentTypeJSON:
			if err := json.Unmarshal(preloadedBody, &inputMap); err != nil {
				logging.Logger().Debug(err.Error())
				return nil, err
			}
			data = inputMap
		case extension.ContentTypeXYAML, extension.ContentTypeTextYAML:
			if err := yaml.Unmarshal(preloadedBody, &inputMap); err != nil {
				logging.Logger().Debug(err.Error())
				return nil, err
			}
			data = conversion.GetUtility().ConvertToStringKeyMap(inputMap)
		}
		container, err := extension.CreateInputContainerByResourceName(resourceName, data)
		if err != nil {
			logging.Logger().Debug(err.Error())
			return nil, err
		}
		if err := mapstruct.GetUtility().MapToStruct(data, container); err != nil {
			logging.Logger().Debug(err.Error())
			return nil, err
		}
		if err := executeValidation(c, resourceName, container, c.Request.URL.Query().Get("key_parameter")); err != nil {
			return nil, err
		}
		return container, nil
	case extension.ContentTypeMultipartFormData:
		inputMap := map[string]interface{}{}
		container, err := extension.CreateInputContainerByResourceName(resourceName, inputMap)
		if err != nil {
			logging.Logger().Debug(err.Error())
			return nil, err
		}
		vs := reflect.ValueOf(container)
		for vs.Kind() == reflect.Ptr {
			vs = vs.Elem()
		}
		if !vs.IsValid() {
			logging.Logger().Debug("invalid model")
			return nil, errors.New("invalid model")
		}
		if !vs.CanInterface() {
			logging.Logger().Debug("invalid model")
			return nil, errors.New("invalid model")
		}
		value := vs.Interface()
		t := reflect.TypeOf(value)
		c.Bind(container)
		if c.Request.ParseMultipartForm(1024*1024) == nil {
			for formKey := range c.Request.Form {
				formValue := c.Request.Form.Get(formKey)
				submatchList := formKeyHashRegExp.FindStringSubmatch(formKey)
				if len(submatchList) == 3 {
					formMainKey := submatchList[1]
					formSubKey := submatchList[2]
					for i := 0; i < t.NumField(); i++ {
						field := t.Field(i)
						formTag := getMapingTagValue(&field, "form")
						if formTag == formMainKey {
							switch field.Type.String() {
							case stringInterfaceMapTypeString:
								if vs.FieldByName(field.Name).IsNil() {
									vs.FieldByName(field.Name).Set(reflect.ValueOf(map[string]interface{}{}))
								}
								vs.FieldByName(field.Name).SetMapIndex(reflect.ValueOf(formSubKey), reflect.ValueOf(formValue))
								break
							default:
								logging.Logger().Debug("invalid field definition, the field must be map[string]interface{}")
								return nil, errors.New("invalid field definition, the field must be map[string]interface{}")
							}
						}
					}
				} else {
					for i := 0; i < t.NumField(); i++ {
						field := t.Field(i)
						formTag := getMapingTagValue(&field, "form")
						if formTag == formKey {
							switch field.Type.String() {
							case intTypeString, int8TypeString, int16TypeString, int32TypeString, int64TypeString:
								intValue, err := strconv.ParseInt(formValue, 10, 64)
								if err != nil {
									logging.Logger().Debug(err.Error())
									return nil, err
								}
								vs.FieldByName(field.Name).SetInt(intValue)
								break
							case uintTypeString, uint8TypeString, uint16TypeString, uint32TypeString, uint64TypeString:
								uintValue, err := strconv.ParseUint(formValue, 10, 64)
								if err != nil {
									logging.Logger().Debug(err.Error())
									return nil, err
								}
								vs.FieldByName(field.Name).SetUint(uintValue)
								break
							case float32TypeString, float64TypeString:
								floatValue, err := strconv.ParseFloat(formValue, 64)
								if err != nil {
									logging.Logger().Debug(err.Error())
									return nil, err
								}
								vs.FieldByName(field.Name).SetFloat(floatValue)
								break
							case booleanTypeString:
								booleanValue, err := strconv.ParseBool(formValue)
								if err != nil {
									logging.Logger().Debug(err.Error())
									return nil, err
								}
								vs.FieldByName(field.Name).SetBool(booleanValue)
								break
							case stringTypeString:
								vs.FieldByName(field.Name).SetString(formValue)
								break
							case bytesTypeString:
								vs.FieldByName(field.Name).SetBytes([]byte(formValue))
								break
							default:
								logging.Logger().Debug("invalid field definition, the field must be string or slice of bytes")
								return nil, errors.New("invalid field definition, the field must be string or slice of bytes")
							}
						}
					}
				}
			}
			files := c.Request.MultipartForm.File
			for formKey := range files {
				buffer := &bytes.Buffer{}
				file, _, err := c.Request.FormFile(formKey)
				if err != nil {
					logging.Logger().Debug(err.Error())
					return nil, err
				}
				defer file.Close()
				data, err := ioutil.ReadAll(file)
				if err != nil {
					logging.Logger().Debug(err.Error())
					return nil, err
				}
				_, err = buffer.Write(data)
				if err != nil {
					logging.Logger().Debug(err.Error())
					return nil, err
				}
				submatchList := formKeyHashRegExp.FindStringSubmatch(formKey)
				if len(submatchList) == 3 {
					formMainKey := submatchList[1]
					formSubKey := submatchList[2]
					for i := 0; i < t.NumField(); i++ {
						field := t.Field(i)
						formTag := getMapingTagValue(&field, "form")
						if formTag == formMainKey {
							switch field.Type.String() {
							case stringInterfaceMapTypeString:
								if vs.FieldByName(field.Name).IsNil() {
									vs.FieldByName(field.Name).Set(reflect.ValueOf(map[string]interface{}{}))
								}
								vs.FieldByName(field.Name).SetMapIndex(reflect.ValueOf(formSubKey), reflect.ValueOf(buffer.Bytes()))
								break
							default:
								logging.Logger().Debug("invalid field definition, the field must be map[string]interface{}")
								return nil, errors.New("invalid field definition, the field must be map[string]interface{}")
							}
						}
					}
				} else {
					for i := 0; i < t.NumField(); i++ {
						field := t.Field(i)
						formTag := getMapingTagValue(&field, "form")
						if formTag == formKey {
							switch field.Type.String() {
							case stringTypeString:
								vs.FieldByName(field.Name).SetString(buffer.String())
								break
							case bytesTypeString:
								vs.FieldByName(field.Name).SetBytes(buffer.Bytes())
								break
							default:
								logging.Logger().Debug("invalid field definition, the field must be string or slice of bytes")
								return nil, errors.New("invalid field definition, the field must be string or slice of bytes")
							}
						}
					}
				}
			}
		}
		if err := executeValidation(c, resourceName, container, c.Request.URL.Query().Get("key_parameter")); err != nil {
			return nil, err
		}
		return container, nil
	}
	return nil, fmt.Errorf("Content-Type %s is not supported", c.ContentType())
}
func (receiver *BaseController) GetModel() extension.Model {
	return receiver.model
}
func (receiver *BaseController) GetResourceName() (string, error) {
	return extension.GetAssociatedResourceNameWithModel(receiver.model)
}