package callbacks

import (
	
	

	
	
	
	
)

func ( bool) func( *gorm.DB) {
	return func( *gorm.DB) {
		if .Error == nil && .Statement.Schema != nil {
			,  := .Statement.SelectAndOmitColumns(, !)

			// Save Belongs To associations
			for ,  := range .Statement.Schema.Relationships.BelongsTo {
				if ,  := [.Name]; ( && !) || (! && ) {
					continue
				}

				 := func( reflect.Value,  reflect.Value) {
					for ,  := range .References {
						if !.OwnPrimaryKey {
							,  := .PrimaryKey.ValueOf(.Statement.Context, )
							.AddError(.ForeignKey.Set(.Statement.Context, , ))

							if ,  := .Statement.Dest.(map[string]interface{});  {
								[.ForeignKey.DBName] = 
								if ,  := [.Name];  {
									[.Name] = .Interface()
								}
							}
						}
					}
				}

				switch .Statement.ReflectValue.Kind() {
				case reflect.Slice, reflect.Array:
					var (
						   = .Statement.ReflectValue.Len()
						      = make([]reflect.Value, 0, )
						 = .Field.FieldType
						     = .Kind() == reflect.Ptr
					)

					if ! {
						 = reflect.PtrTo()
					}

					 := reflect.MakeSlice(reflect.SliceOf(), 0, 10)
					 := reflect.MakeSlice(reflect.SliceOf(), 0, 10)
					 := map[string]bool{}
					for  := 0;  < ; ++ {
						 := .Statement.ReflectValue.Index()
						if reflect.Indirect().Kind() != reflect.Struct {
							break
						}
						if ,  := .Field.ValueOf(.Statement.Context, ); ! { // check belongs to relation value
							 := .Field.ReflectValueOf(.Statement.Context, ) // relation reflect value
							if ! {
								 = .Addr()
							}
							 = append(, )
							 = reflect.Append(, )

							 := make([]interface{}, 0, len(.FieldSchema.PrimaryFields))
							for ,  := range .FieldSchema.PrimaryFields {
								if ,  := .ValueOf(.Statement.Context, ); ! {
									 = append(, )
								}
							}
							 := utils.ToStringKey(...)
							if len() != len(.FieldSchema.PrimaryFields) || ![] {
								if  != "" { // has primary fields
									[] = true
								}

								 = reflect.Append(, )
							}
						}
					}

					if .Len() > 0 {
						if saveAssociations(, , , , , nil) == nil {
							for  := 0;  < .Len(); ++ {
								([], .Index())
							}
						}
					}
				case reflect.Struct:
					if ,  := .Field.ValueOf(.Statement.Context, .Statement.ReflectValue); ! {
						 := .Field.ReflectValueOf(.Statement.Context, .Statement.ReflectValue) // relation reflect value
						if .Kind() != reflect.Ptr {
							 = .Addr()
						}

						if saveAssociations(, , , , , nil) == nil {
							(.Statement.ReflectValue, )
						}
					}
				}
			}
		}
	}
}

func ( bool) func( *gorm.DB) {
	return func( *gorm.DB) {
		if .Error == nil && .Statement.Schema != nil {
			,  := .Statement.SelectAndOmitColumns(, !)

			// Save Has One associations
			for ,  := range .Statement.Schema.Relationships.HasOne {
				if ,  := [.Name]; ( && !) || (! && ) {
					continue
				}

				switch .Statement.ReflectValue.Kind() {
				case reflect.Slice, reflect.Array:
					var (
						 = .Field.FieldType
						     = .Kind() == reflect.Ptr
					)

					if ! {
						 = reflect.PtrTo()
					}

					 := reflect.MakeSlice(reflect.SliceOf(), 0, 10)

					for  := 0;  < .Statement.ReflectValue.Len(); ++ {
						 := .Statement.ReflectValue.Index()

						if reflect.Indirect().Kind() == reflect.Struct {
							if ,  := .Field.ValueOf(.Statement.Context, ); ! {
								 := .Field.ReflectValueOf(.Statement.Context, )
								if .Kind() != reflect.Ptr {
									 = .Addr()
								}

								for ,  := range .References {
									if .OwnPrimaryKey {
										,  := .PrimaryKey.ValueOf(.Statement.Context, )
										.AddError(.ForeignKey.Set(.Statement.Context, , ))
									} else if .PrimaryValue != "" {
										.AddError(.ForeignKey.Set(.Statement.Context, , .PrimaryValue))
									}
								}

								 = reflect.Append(, )
							}
						}
					}

					if .Len() > 0 {
						 := make([]string, 0, len(.References))
						for ,  := range .References {
							 = append(, .ForeignKey.DBName)
						}

						saveAssociations(, , , , , )
					}
				case reflect.Struct:
					if ,  := .Field.ValueOf(.Statement.Context, .Statement.ReflectValue); ! {
						 := .Field.ReflectValueOf(.Statement.Context, .Statement.ReflectValue)
						if .Kind() != reflect.Ptr {
							 = .Addr()
						}

						 := make([]string, 0, len(.References))
						for ,  := range .References {
							if .OwnPrimaryKey {
								,  := .PrimaryKey.ValueOf(.Statement.Context, .Statement.ReflectValue)
								.AddError(.ForeignKey.Set(.Statement.Context, , ))
							} else if .PrimaryValue != "" {
								.AddError(.ForeignKey.Set(.Statement.Context, , .PrimaryValue))
							}
							 = append(, .ForeignKey.DBName)
						}

						saveAssociations(, , , , , )
					}
				}
			}

			// Save Has Many associations
			for ,  := range .Statement.Schema.Relationships.HasMany {
				if ,  := [.Name]; ( && !) || (! && ) {
					continue
				}

				 := .Field.IndirectFieldType.Elem()
				 := .Kind() == reflect.Ptr
				if ! {
					 = reflect.PtrTo()
				}
				 := reflect.MakeSlice(reflect.SliceOf(), 0, 10)
				 := map[string]bool{}
				 := func( reflect.Value) {
					if ,  := .Field.ValueOf(.Statement.Context, ); ! {
						 := reflect.Indirect(.Field.ReflectValueOf(.Statement.Context, ))

						for  := 0;  < .Len(); ++ {
							 := .Index()
							for ,  := range .References {
								if .OwnPrimaryKey {
									,  := .PrimaryKey.ValueOf(.Statement.Context, )
									.AddError(.ForeignKey.Set(.Statement.Context, , ))
								} else if .PrimaryValue != "" {
									.AddError(.ForeignKey.Set(.Statement.Context, , .PrimaryValue))
								}
							}

							 := make([]interface{}, 0, len(.FieldSchema.PrimaryFields))
							for ,  := range .FieldSchema.PrimaryFields {
								if ,  := .ValueOf(.Statement.Context, ); ! {
									 = append(, )
								}
							}

							 := utils.ToStringKey(...)
							if len() != len(.FieldSchema.PrimaryFields) || ![] {
								if  != "" { // has primary fields
									[] = true
								}

								if  {
									 = reflect.Append(, )
								} else {
									 = reflect.Append(, .Addr())
								}
							}
						}
					}
				}

				switch .Statement.ReflectValue.Kind() {
				case reflect.Slice, reflect.Array:
					for  := 0;  < .Statement.ReflectValue.Len(); ++ {
						 := .Statement.ReflectValue.Index()
						if reflect.Indirect().Kind() == reflect.Struct {
							()
						}
					}
				case reflect.Struct:
					(.Statement.ReflectValue)
				}

				if .Len() > 0 {
					 := make([]string, 0, len(.References))
					for ,  := range .References {
						 = append(, .ForeignKey.DBName)
					}

					saveAssociations(, , , , , )
				}
			}

			// Save Many2Many associations
			for ,  := range .Statement.Schema.Relationships.Many2Many {
				if ,  := [.Name]; ( && !) || (! && ) {
					continue
				}

				 := .Field.IndirectFieldType.Elem()
				 := .Kind() == reflect.Ptr
				if ! {
					 = reflect.PtrTo()
				}
				 := reflect.MakeSlice(reflect.SliceOf(), 0, 10)
				 := reflect.MakeSlice(reflect.SliceOf(), 0, 10)
				 := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(.JoinTable.ModelType)), 0, 10)
				 := []reflect.Value{}

				 := func( reflect.Value,  reflect.Value) {
					 := reflect.New(.JoinTable.ModelType)
					for ,  := range .References {
						if .OwnPrimaryKey {
							,  := .PrimaryKey.ValueOf(.Statement.Context, )
							.AddError(.ForeignKey.Set(.Statement.Context, , ))
						} else if .PrimaryValue != "" {
							.AddError(.ForeignKey.Set(.Statement.Context, , .PrimaryValue))
						} else {
							,  := .PrimaryKey.ValueOf(.Statement.Context, )
							.AddError(.ForeignKey.Set(.Statement.Context, , ))
						}
					}
					 = reflect.Append(, )
				}

				 := map[string]bool{}
				 := func( reflect.Value) {
					if ,  := .Field.ValueOf(.Statement.Context, ); ! {
						 := reflect.Indirect(.Field.ReflectValueOf(.Statement.Context, ))
						for  := 0;  < .Len(); ++ {
							 := .Index()
							if ! {
								 = .Addr()
							}
							 = append(, )
							 = reflect.Append(, )

							 := make([]interface{}, 0, len(.FieldSchema.PrimaryFields))
							for ,  := range .FieldSchema.PrimaryFields {
								if ,  := .ValueOf(.Statement.Context, ); ! {
									 = append(, )
								}
							}

							 := utils.ToStringKey(...)
							if len() != len(.FieldSchema.PrimaryFields) || ![] {
								if  != "" { // has primary fields
									[] = true
								}

								 = reflect.Append(, )
							}

						}
					}
				}

				switch .Statement.ReflectValue.Kind() {
				case reflect.Slice, reflect.Array:
					for  := 0;  < .Statement.ReflectValue.Len(); ++ {
						 := .Statement.ReflectValue.Index()
						if reflect.Indirect().Kind() == reflect.Struct {
							()
						}
					}
				case reflect.Struct:
					(.Statement.ReflectValue)
				}

				// optimize elems of reflect value length
				if  := .Len();  > 0 {
					if ,  := [.Name+".*"]; ! ||  {
						saveAssociations(, , , , , nil)
					}

					for  := 0;  < ; ++ {
						([], .Index())
					}
				}

				if .Len() > 0 {
					.AddError(.Session(&gorm.Session{NewDB: true}).Clauses(clause.OnConflict{DoNothing: true}).Session(&gorm.Session{
						SkipHooks:                .Statement.SkipHooks,
						DisableNestedTransaction: true,
					}).Create(.Interface()).Error)
				}
			}
		}
	}
}

func onConflictOption( *gorm.Statement,  *schema.Schema,  []string) ( clause.OnConflict) {
	if len() > 0 || .DB.FullSaveAssociations {
		.Columns = make([]clause.Column, 0, len(.PrimaryFieldDBNames))
		for ,  := range .PrimaryFieldDBNames {
			.Columns = append(.Columns, clause.Column{Name: })
		}

		.UpdateAll = .DB.FullSaveAssociations
		if !.UpdateAll {
			.DoUpdates = clause.AssignmentColumns()
		}
	} else {
		.DoNothing = true
	}

	return
}

func saveAssociations( *gorm.DB,  *schema.Relationship,  reflect.Value,  map[string]bool,  bool,  []string) error {
	// stop save association loop
	if checkAssociationsSaved(, ) {
		return nil
	}

	var (
		,  []string
		     = onConflictOption(.Statement, .FieldSchema, )
		        = .Name + "."
		         = .Interface()
	)

	for ,  := range  {
		 := ""
		if strings.HasPrefix(, ) {
			 = strings.TrimPrefix(, )
		}

		if  != "" {
			if  {
				 = append(, )
			} else {
				 = append(, )
			}
		}
	}

	 := .Session(&gorm.Session{NewDB: true}).Clauses().Session(&gorm.Session{
		FullSaveAssociations:     .FullSaveAssociations,
		SkipHooks:                .Statement.SkipHooks,
		DisableNestedTransaction: true,
	})

	.Statement.Settings.Range(func(,  interface{}) bool {
		.Statement.Settings.Store(, )
		return true
	})

	if .Statement.FullSaveAssociations {
		 = .Set("gorm:update_track_time", true)
	}

	if len() > 0 {
		 = .Select()
	} else if  && len() == 0 {
		 = .Omit(clause.Associations)
	}

	if len() > 0 {
		 = .Omit(...)
	}

	return .AddError(.Create().Error)
}

// check association values has been saved
// if values kind is Struct, check it has been saved
// if values kind is Slice/Array, check all items have been saved
var visitMapStoreKey = "gorm:saved_association_map"

func checkAssociationsSaved( *gorm.DB,  reflect.Value) bool {
	if ,  := .Get(visitMapStoreKey);  {
		if ,  := .(*visitMap);  {
			if loadOrStoreVisitMap(, ) {
				return true
			}
		}
	} else {
		 := make(visitMap)
		loadOrStoreVisitMap(&, )
		.Set(visitMapStoreKey, &)
	}

	return false
}