package orm

import (
	
	
	

	
)

var _tables = newTables()

type tableInProgress struct {
	table *Table

	init1Once sync.Once
	init2Once sync.Once
}

func ( *Table) *tableInProgress {
	return &tableInProgress{
		table: ,
	}
}

func ( *tableInProgress) () bool {
	var  bool
	.init1Once.Do(func() {
		.table.init1()
		 = true
	})
	return 
}

func ( *tableInProgress) () bool {
	var  bool
	.init2Once.Do(func() {
		.table.init2()
		 = true
	})
	return 
}

// GetTable returns a Table for a struct type.
func ( reflect.Type) *Table {
	return _tables.Get()
}

// RegisterTable registers a struct as SQL table.
// It is usually used to register intermediate table
// in many to many relationship.
func ( interface{}) {
	_tables.Register()
}

type tables struct {
	tables sync.Map

	mu         sync.RWMutex
	inProgress map[reflect.Type]*tableInProgress
}

func () *tables {
	return &tables{
		inProgress: make(map[reflect.Type]*tableInProgress),
	}
}

func ( *tables) ( interface{}) {
	 := reflect.TypeOf()
	if .Kind() == reflect.Ptr {
		 = .Elem()
	}
	_ = .Get()
}

func ( *tables) ( reflect.Type,  bool) *Table {
	if .Kind() != reflect.Struct {
		panic(fmt.Errorf("got %s, wanted %s", .Kind(), reflect.Struct))
	}

	if ,  := .tables.Load();  {
		return .(*Table)
	}

	.mu.Lock()

	if ,  := .tables.Load();  {
		.mu.Unlock()
		return .(*Table)
	}

	var  *Table

	 := .inProgress[]
	if  == nil {
		 = newTable()
		 = newTableInProgress()
		.inProgress[] = 
	} else {
		 = .table
	}

	.mu.Unlock()

	.init1()
	if  {
		return 
	}

	if .init2() {
		.mu.Lock()
		delete(.inProgress, )
		.tables.Store(, )
		.mu.Unlock()
	}

	return 
}

func ( *tables) ( reflect.Type) *Table {
	return .get(, false)
}

func ( *tables) ( types.Safe) *Table {
	var  *Table
	.tables.Range(func(,  interface{}) bool {
		 := .(*Table)
		if .SQLName ==  {
			 = 
			return false
		}
		return true
	})
	return 
}