// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
// 🤖 Github Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io

package fiber

import (
	
	
	
	
)

// Put fields related to mounting.
type mountFields struct {
	// Mounted and main apps
	appList map[string]*App
	// Ordered keys of apps (sorted by key length for Render)
	appListKeys []string
	// check added routes of sub-apps
	subAppsRoutesAdded sync.Once
	// check mounted sub-apps
	subAppsProcessed sync.Once
	// Prefix of app if it was mounted
	mountPath string
}

// Create empty mountFields instance
func newMountFields( *App) *mountFields {
	return &mountFields{
		appList:     map[string]*App{"": },
		appListKeys: make([]string, 0),
	}
}

// Mount attaches another app instance as a sub-router along a routing path.
// It's very useful to split up a large API as many independent routers and
// compose them as a single service using Mount. The fiber's error handler and
// any of the fiber's sub apps are added to the application's error handlers
// to be invoked on errors that happen within the prefix route.
func ( *App) ( string,  *App) Router {
	 = strings.TrimRight(, "/")
	if  == "" {
		 = "/"
	}

	// Support for configs of mounted-apps and sub-mounted-apps
	for ,  := range .mountFields.appList {
		 := getGroupPath(, )

		.mountFields.mountPath = 
		.mountFields.appList[] = 
	}

	// register mounted group
	 := &Group{Prefix: , app: }
	.register(methodUse, , )

	// Execute onMount hooks
	if  := .hooks.executeOnMountHooks();  != nil {
		panic()
	}

	return 
}

// Mount attaches another app instance as a sub-router along a routing path.
// It's very useful to split up a large API as many independent routers and
// compose them as a single service using Mount.
func ( *Group) ( string,  *App) Router {
	 := getGroupPath(.Prefix, )
	 = strings.TrimRight(, "/")
	if  == "" {
		 = "/"
	}

	// Support for configs of mounted-apps and sub-mounted-apps
	for ,  := range .mountFields.appList {
		 := getGroupPath(, )

		.mountFields.mountPath = 
		.app.mountFields.appList[] = 
	}

	// register mounted group
	 := &Group{Prefix: , app: }
	.app.register(methodUse, , )

	// Execute onMount hooks
	if  := .hooks.executeOnMountHooks(.app);  != nil {
		panic()
	}

	return 
}

// The MountPath property contains one or more path patterns on which a sub-app was mounted.
func ( *App) () string {
	return .mountFields.mountPath
}

// hasMountedApps Checks if there are any mounted apps in the current application.
func ( *App) () bool {
	return len(.mountFields.appList) > 1
}

// mountStartupProcess Handles the startup process of mounted apps by appending sub-app routes, generating app list keys, and processing sub-app routes.
func ( *App) () {
	if .hasMountedApps() {
		// add routes of sub-apps
		.mountFields.subAppsProcessed.Do(func() {
			.appendSubAppLists(.mountFields.appList)
			.generateAppListKeys()
		})
		// adds the routes of the sub-apps to the current application.
		.mountFields.subAppsRoutesAdded.Do(func() {
			.processSubAppsRoutes()
		})
	}
}

// generateAppListKeys generates app list keys for Render, should work after appendSubAppLists
func ( *App) () {
	for  := range .mountFields.appList {
		.mountFields.appListKeys = append(.mountFields.appListKeys, )
	}

	sort.Slice(.mountFields.appListKeys, func(,  int) bool {
		return len(.mountFields.appListKeys[]) < len(.mountFields.appListKeys[])
	})
}

// appendSubAppLists supports nested for sub apps
func ( *App) ( map[string]*App,  ...string) {
	// Optimize: Cache parent prefix
	 := ""
	if len() > 0 {
		 = [0]
	}

	for ,  := range  {
		// skip real app
		if  == "" {
			continue
		}

		if  != "" {
			 = getGroupPath(, )
		}

		if ,  := .mountFields.appList[]; ! {
			.mountFields.appList[] = 
		}

		// The first element of appList is always the app itself. If there are no other sub apps, we should skip appending nested apps.
		if len(.mountFields.appList) > 1 {
			.(.mountFields.appList, )
		}
	}
}

// processSubAppsRoutes adds routes of sub-apps recursively when the server is started
func ( *App) () {
	for ,  := range .mountFields.appList {
		// skip real app
		if  == "" {
			continue
		}
		// process the inner routes
		if .hasMountedApps() {
			.mountFields.subAppsRoutesAdded.Do(func() {
				.()
			})
		}
	}
	var  uint32
	var  uint32
	// Iterate over the stack of the parent app
	for  := range .stack {
		// Iterate over each route in the stack
		 := len(.stack[])
		for  := 0;  < ; ++ {
			 := .stack[][]
			// Check if the route has a mounted app
			if !.mount {
				++
				// If not, update the route's position and continue
				.pos = 
				if !.use || (.use &&  == 0) {
					 += uint32(len(.Handlers))
				}
				continue
			}

			// Create a slice to hold the sub-app's routes
			 := make([]*Route, len(.group.app.stack[]))

			// Iterate over the sub-app's routes
			for ,  := range .group.app.stack[] {
				// Clone the sub-app's route
				 := .copyRoute()

				// Add the parent route's path as a prefix to the sub-app's route
				.addPrefixToRoute(.path, )

				// Add the cloned sub-app's route to the slice of sub-app routes
				[] = 
			}

			// Insert the sub-app's routes into the parent app's stack
			 := make([]*Route, len(.stack[])+len()-1)
			copy([:], .stack[][:])
			copy([:+len()], )
			copy([+len():], .stack[][+1:])
			.stack[] = 

			// Decrease the parent app's route count to account for the mounted app's original route
			atomic.AddUint32(&.routesCount, ^uint32(0))
			--
			// Increase the parent app's route count to account for the sub-app's routes
			atomic.AddUint32(&.routesCount, uint32(len()))

			// Mark the parent app's routes as refreshed
			.routesRefreshed = true
			// update stackLen after appending subRoutes to app.stack[m]
			 = len(.stack[])
		}
	}
	atomic.StoreUint32(&.handlersCount, )
}