// Copyright (c) Shenyang Leading Edge Intelligent Technology Co., Ltd. All rights reserved.

package container

import (
	"github.com/go-xorm/xorm"
	"reflect"
	"testing"
)

func FactoryWithoutResult() {
}

type TestElement interface {
}

type TestElementImplement struct {
}

func FactoryOfNullTestElement() TestElement {
	return nil
}

func FactoryOfElementTestInterfaceWithContent(string) TestElement {
	return &TestElementImplement{}
}

func FactoryOfTestElementImplement() *TestElementImplement {
	return &TestElementImplement{}
}

func FactoryOfTestElement() TestElement {
	return &TestElementImplement{}
}

func FactoryWithTooManyResults() (TestElement, TestService) {
	return &TestElementImplement{}, &TestServiceImplement{}
}

var testElementType = reflect.TypeOf((*TestElement)(nil)).Elem()

var elementInstance = Instance(reflect.ValueOf(FactoryOfTestElement()))

type TestService interface {
	String() (string, error)
	StringWithContext(*RequestContext) (string, error)
	StringNotFirstContext(string, *RequestContext) (string, error)
	String2() (string, string, error)
	String3(*RequestContext, *RequestContext) error
	NoError() string
}

type TestToString interface {
	String() string
}

type TestServiceImplement struct {
	content string
}

func (impl *TestServiceImplement) String() (string, error) {
	return impl.content, nil
}

func (impl *TestServiceImplement) StringWithContext(_ *RequestContext) (string, error) {
	return impl.content, nil
}

func (impl *TestServiceImplement) StringNotFirstContext(_ string, _ *RequestContext) (string, error) {
	return "", nil
}

func (impl *TestServiceImplement) String2() (string, string, error) {
	return impl.content, impl.content, nil
}

func (impl *TestServiceImplement) String3(_ *RequestContext, _ *RequestContext) error {
	return nil
}

func (impl *TestServiceImplement) NoError() string {
	return impl.content
}

func FactoryOfTestService() TestService {
	return &TestServiceImplement{}
}

func FactoryOfServiceTestInterfaceWithContent(content string) TestService {
	return &TestServiceImplement{content}
}

type TestServiceImplementWithContext struct {
	context *SessionContext
}

func (impl *TestServiceImplementWithContext) String() (string, error) {
	return "", nil
}

func (impl *TestServiceImplementWithContext) StringWithContext(_ *RequestContext) (string, error) {
	return "", nil
}

func (impl *TestServiceImplementWithContext) StringNotFirstContext(_ string, _ *RequestContext) (string, error) {
	return "", nil
}

func (impl *TestServiceImplementWithContext) String2() (string, string, error) {
	return "", "", nil
}

func (impl *TestServiceImplementWithContext) String3(_ *RequestContext, _ *RequestContext) error {
	return nil
}

func (impl *TestServiceImplementWithContext) NoError() string {
	return ""
}

func (impl *TestServiceImplementWithContext) SetContext(context *SessionContext) {
	impl.context = context
}

type TestWithTooManyInSetContext interface {
	SetContext(*SessionContext, string)
}

type TestWithTooManyInSetContextImplement struct {
	context *SessionContext
}

func (impl *TestWithTooManyInSetContextImplement) SetContext(_ *SessionContext, _ string) {
}

func FactoryOfTestWithTooManyInSetContext() TestWithTooManyInSetContext {
	return &TestWithTooManyInSetContextImplement{}
}

type TestWithReturnValueSetContext interface {
	SetContext(*SessionContext) error
}

type TestWithReturnValueSetContextImplement struct {
	context *SessionContext
}

func (impl *TestWithReturnValueSetContextImplement) SetContext(context *SessionContext) error {
	impl.context = context
	return nil
}

func FactoryOfTestWithReturnValueSetContext() TestWithReturnValueSetContext {
	return &TestWithReturnValueSetContextImplement{}
}

type TestWithErrorInSetContext interface {
	SetContext(string)
}

type TestWithErrorInSetContextImplement struct {
	context *SessionContext
}

func (impl *TestWithErrorInSetContextImplement) SetContext(_ string) {
}

func FactoryOfTestWithErrorInSetContext() TestWithErrorInSetContext {
	return &TestWithErrorInSetContextImplement{}
}

type TestWithNoInSetContext interface {
	SetContext()
}

type TestWithNoInSetContextImplement struct {
	context *SessionContext
}

func (impl *TestWithNoInSetContextImplement) SetContext() {
}

func FactoryOfTestWithNoInSetContext() TestWithNoInSetContext {
	return &TestWithNoInSetContextImplement{}
}

type TestToStringImplement struct {
	context *SessionContext
}

func (impl TestToStringImplement) String() string {
	return ""
}

func FactoryOfTestServiceWithContext() TestService {
	return &TestServiceImplementWithContext{}
}

func FactoryOfTestServiceImplementWithContext() *TestServiceImplementWithContext {
	return &TestServiceImplementWithContext{}
}

func FactoryOfTestServiceImplementWithContextStruct() TestServiceImplementWithContext {
	return TestServiceImplementWithContext{}
}

func FactoryOfNullTestService() TestService {
	return nil
}

func FactoryOfNullTestServiceImplementWithContext() *TestServiceImplementWithContext {
	return nil
}

func FactoryOfInt() *int {
	intValue := 123
	return &intValue
}

func FactoryOfTestToString() TestToString {
	return TestToStringImplement{}
}

var testServiceType = reflect.TypeOf((*TestService)(nil)).Elem()

var serviceInstance = Instance(reflect.ValueOf(FactoryOfTestService()))

type TestCallerBrokerBuilderImplementWithError struct {
	checkingError error
	buildingError error
}

func (impl *TestCallerBrokerBuilderImplementWithError) Check(_ Method) error {

	return impl.checkingError
}

func (impl *TestCallerBrokerBuilderImplementWithError) Build(_ *SessionContext, _ Caller) (Caller, error) {

	return nil, impl.buildingError
}

type TestCallerBrokerBuilderImplement struct {
}

func (impl *TestCallerBrokerBuilderImplement) Check(_ Method) error {

	return nil
}

func (impl *TestCallerBrokerBuilderImplement) Build(_ *SessionContext, caller Caller) (Caller, error) {

	return caller, nil
}

type TransactionHandlerMock struct {
	closeNumberOfTimes  int
	beginNumberOfTimes  int
	beginError          error
	commitNumberOfTimes int
	commitError         error
	session             *xorm.Session
}

func (mock *TransactionHandlerMock) Close() {
	mock.closeNumberOfTimes++
}

func (mock *TransactionHandlerMock) Begin() error {
	mock.beginNumberOfTimes++
	return mock.beginError
}

func (mock *TransactionHandlerMock) Commit() error {
	mock.commitNumberOfTimes++
	return mock.commitError
}

func (mock *TransactionHandlerMock) Session() *xorm.Session {
	return mock.session
}

type TransactionHandlerFactoryMock struct {
	handler     *TransactionHandlerMock
	createError error
}

// @Reference LAPP_LF_MOM_BACKEND/container/TransactionHandlerFactory.Create
func (mock *TransactionHandlerFactoryMock) Create() (TransactionHandler, error) {
	return mock.handler, mock.createError
}

var transactionHandlerFactoryMock TransactionHandlerFactory = &TransactionHandlerFactoryMock{}

func TestContainer_ParseFactory(t *testing.T) {

	_, _ = parseFactory(FactoryOfTestElement)
}

func TestContainer_ParseFactory_NullError(t *testing.T) {
	defer func() {
		if err := recover(); err != "工厂不能为空!" {
			t.Fatalf("意外错误:%s", err)
		}
	}()

	_, _ = parseFactory(nil)
	t.Fatalf("意外的没有错误!")
}

func TestContainer_ParseFactory_FactoryTypeError(t *testing.T) {
	defer func() {
		if err := recover(); err != "工厂必须是func!" {
			t.Fatalf("意外错误:%s", err)
		}
	}()

	_, _ = parseFactory(reflect.TypeOf(FactoryOfTestElement()))
	t.Fatalf("意外的没有错误!")
}

func TestContainer_ParseFactory_ParameterCountError(t *testing.T) {
	defer func() {
		if err := recover(); err != "工厂不能有参数!" {
			t.Fatalf("意外错误:%s", err)
		}
	}()

	_, _ = parseFactory(FactoryOfElementTestInterfaceWithContent)
	t.Fatalf("意外的没有错误!")
}

func TestContainer_ParseFactory_NoReturnValueError(t *testing.T) {
	defer func() {
		if err := recover(); err != "工厂必值需有返回值!" {
			t.Fatalf("意外错误:%s", err)
		}
	}()

	_, _ = parseFactory(FactoryWithoutResult)
	t.Fatalf("意外的没有错误!")
}

func TestContainer_ParseFactory_TooManyResultsError(t *testing.T) {
	defer func() {
		if err := recover(); err != "工厂只能有一个返回值!" {
			t.Fatalf("意外错误:%s", err)
		}
	}()

	_, _ = parseFactory(FactoryWithTooManyResults)
	t.Fatalf("意外的没有错误!")
}

func TestContainer_ParseFactory_ReturnValueTypeError(t *testing.T) {
	defer func() {
		if err := recover(); err != "工厂的返回值必需是interface!" {
			t.Fatalf("意外错误:%s", err)
		}
	}()

	_, _ = parseFactory(FactoryOfTestElementImplement)
	t.Fatalf("意外的没有错误!")
}

func call1(_ []reflect.Value) []reflect.Value {
	return []reflect.Value{reflect.ValueOf(1)}
}

func call2(_ []reflect.Value) []reflect.Value {
	return []reflect.Value{reflect.ValueOf(2)}
}

func TestContainer_Caller_Equal_NullCaller1AndCaller2(t *testing.T) {

	if !CallerEqual(nil, nil) {
		t.Fatalf("意外的不相等!")
	}
}

func TestContainer_Caller_Equal_NullCaller1(t *testing.T) {

	if CallerEqual(nil, call1) {
		t.Fatalf("意外的相等!")
	}
}

func TestContainer_Caller_Equal_NullCaller2(t *testing.T) {

	if CallerEqual(call1, nil) {
		t.Fatalf("意外的相等!")
	}
}

func TestContainer_Caller_Equal_NotNull(t *testing.T) {

	var caller1 = call1
	var caller2 = call1
	var caller3 = call2
	if !CallerEqual(caller1, caller2) {
		t.Fatalf("意外的不相等!")
	}
	if CallerEqual(caller2, caller3) {
		t.Fatalf("意外的相等!")
	}
	call3 := func(_ []reflect.Value) []reflect.Value {
		return []reflect.Value{reflect.ValueOf(3)}
	}
	call4 := func(_ []reflect.Value) []reflect.Value {
		return []reflect.Value{reflect.ValueOf(4)}
	}
	var caller4 = call3
	var caller5 = call3
	var caller6 = call4
	if !CallerEqual(caller4, caller5) {
		t.Fatalf("意外的不相等!")
	}
	if CallerEqual(caller5, caller6) {
		t.Fatalf("意外的相等!")
	}
}

type Synchronizer interface {
	Awake()
	Wait()
}

type SynchronizerImplement struct {
	core chan interface{}
}

func NewSynchronizer() Synchronizer {
	return &SynchronizerImplement{make(chan interface{}, 1)}
}

func (impl SynchronizerImplement) Awake() {
	impl.core <- 1
}

func (impl SynchronizerImplement) Wait() {
	<-impl.core
}
