package main
import (
	"context"
	"reflect"
	"strings"
	"unsafe"
	"fmt"
	"github.com/go-pg/pg"
	//"github.com/go-pg/pg/v10/orm"
)
/*func TestPG(opt *pg.Options) *pg.DB {
	println("inside TestPG")
	callfromtestpg()
	db := pg.Connect(opt)
	callfromtestpg2()
	fmt.Println("completed TestPG")
	return db
}*/
type queryHook struct{}
type queryHook1 struct{}

var _ pg.QueryHook = (*queryHook)(nil)
var _ pg.QueryHook1 = (*queryHook1)(nil)
func ReflectStructField(Iface interface{}, FieldName string) bool {
	ValueIface := reflect.ValueOf(Iface)

	// Check if the passed interface is a pointer
	if ValueIface.Type().Kind() != reflect.Ptr {
		// Create a new type of Iface's Type, so we have a pointer to work with
		ValueIface = reflect.New(reflect.TypeOf(Iface))
	}

	// 'dereference' with Elem() and get the field by name
	Field := ValueIface.Elem().FieldByName(FieldName)
	if !Field.IsValid() {
		return false
	}
	return true
}
func getParamWithValuesforpg(query string, args *pg.QueryEvent) string {
	var arguments = make([]string,len(args.Params))
	num_arguments := 0
	var arg1, arg2 string
	var paramValue string
	for _, arg := range args.Params {
		str := fmt.Sprint(arg)
		arguments[num_arguments]=str
		num_arguments++
	}
	if num_arguments == 0 {
		return ""
	}
	//println("query ",query, " num_arguments ",num_arguments)
  foundequal := 0
	arg_count := 0
	words := strings.Fields(query)
	for _, word := range words {
		if foundequal == 1 {
			paramValue += arg2 + ":" + arguments[arg_count] + "\n"
			arg_count++
			//println("paramValue ", paramValue, " arg_count ",arg_count)
			arg2 = ""
			arg1 = ""
			foundequal = 0
			if arg_count >= num_arguments {
				break
			}
		} else {
			foundequal = 0
			if  strings.Contains(word, "=") {
				for i := 0; i < len(word); i++ {
					if word[i] == '=' {
						foundequal = 1
						break
					}
				}
			}

			arg2 = arg1
			arg1 = word
		}
	}
	return paramValue
}

func getParamWithValuesforpg1(query string, args *pg.QueryEvent1) string {
	var arguments = make([]string,len(args.Params))
	num_arguments := 0
	var arg1, arg2 string
	var paramValue string
	for _, arg := range args.Params {
		str := fmt.Sprint(arg)
		arguments[num_arguments]=str
		num_arguments++
	}
	if num_arguments == 0 {
		return ""
	}
	//println("query ",query, " num_arguments ",num_arguments)
  foundequal := 0
	arg_count := 0
	words := strings.Fields(query)
	for _, word := range words {
		if foundequal == 1 {
			paramValue += arg2 + ":" + arguments[arg_count] + "\n"
			arg_count++
			//println("paramValue ", paramValue, " arg_count ",arg_count)
			arg2 = ""
			arg1 = ""
			foundequal = 0
			if arg_count >= num_arguments {
				break
			}
		} else {
			foundequal = 0
			if  strings.Contains(word, "=") {
				for i := 0; i < len(word); i++ {
					if word[i] == '=' {
						foundequal = 1
						break
					}
				}
			}

			arg2 = arg1
			arg1 = word
		}
	}
	return paramValue
}

func TestPG(opt *pg.Options) *pg.DB {
  if opt == nil {
  	return nil
  }
	val := reflect.ValueOf(opt).Elem()
	if strings.Compare(val.Type().Field(3).Name, "OnConnect") == 0 {
		if strings.Compare(val.Type().Field(9).Name, "DialTimeout") == 0 {
			db := pg.Connect(opt)
			//println("add hook")
			db.AddQueryHook(&queryHook{})
			return db
		}
	} else if(strings.Compare(val.Type().Field(3).Name, "User") == 0) {
		var db1 *pg.DB1 = nil
		var opt1 *pg.Options1 = nil
		opt1 = (*pg.Options1)(unsafe.Pointer(opt))
		db1 = pg.Connect1(opt1)

		db1.AddQueryHook(&queryHook1{})
		db := (*pg.DB)(unsafe.Pointer(db1))
		return db
	}

	db := pg.Connect(opt)
	return db
}

func (qh *queryHook1) BeforeQuery(ctx context.Context, evt *pg.QueryEvent1) (context.Context, error) {
	println("inside BeforeQuery1")
	var qry,paramValue string
	sqlQuery, err := evt.FormattedQuery()
	if err != nil {
		return nil, err
	}
	qry =string(sqlQuery)
	paramValue = getParamWithValuesforpg1(qry,evt)
	println("qry2 ",qry, " paramValue ",paramValue)
	return ctx, nil
}
func (queryHook1) AfterQuery(context.Context, *pg.QueryEvent1) error {
	println("inside AfterQuery1")
	return nil
}
func (qh *queryHook) BeforeQuery(ctx context.Context, evt *pg.QueryEvent) (context.Context, error) {
	println("inside BeforeQuery")
	var qry,paramValue string
	xx := ReflectStructField(evt, "fmtedQuery")
	if xx == true {
		sqlQuery, err := evt.FormattedQuery()
		if err != nil {
			return nil, err
		}
		qry =string(sqlQuery)
		paramValue = getParamWithValuesforpg(qry,evt)
		println("qry3 ",qry, " paramValue ",paramValue)
	}
	return ctx, nil
}

func (queryHook) AfterQuery(context.Context, *pg.QueryEvent) error {
	println("inside AfterQuery")
	return nil
}
