// Copyright 2020 Kentaro Hibino. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.

package asynq

import (
	
	
	
	
	
)

// ServeMux is a multiplexer for asynchronous tasks.
// It matches the type of each task against a list of registered patterns
// and calls the handler for the pattern that most closely matches the
// task's type name.
//
// Longer patterns take precedence over shorter ones, so that if there are
// handlers registered for both "images" and "images:thumbnails",
// the latter handler will be called for tasks with a type name beginning with
// "images:thumbnails" and the former will receive tasks with type name beginning
// with "images".
type ServeMux struct {
	mu  sync.RWMutex
	m   map[string]muxEntry
	es  []muxEntry // slice of entries sorted from longest to shortest.
	mws []MiddlewareFunc
}

type muxEntry struct {
	h       Handler
	pattern string
}

// MiddlewareFunc is a function which receives an asynq.Handler and returns another asynq.Handler.
// Typically, the returned handler is a closure which does something with the context and task passed
// to it, and then calls the handler passed as parameter to the MiddlewareFunc.
type MiddlewareFunc func(Handler) Handler

// NewServeMux allocates and returns a new ServeMux.
func () *ServeMux {
	return new(ServeMux)
}

// ProcessTask dispatches the task to the handler whose
// pattern most closely matches the task type.
func ( *ServeMux) ( context.Context,  *Task) error {
	,  := .Handler()
	return .ProcessTask(, )
}

// Handler returns the handler to use for the given task.
// It always return a non-nil handler.
//
// Handler also returns the registered pattern that matches the task.
//
// If there is no registered handler that applies to the task,
// handler returns a 'not found' handler which returns an error.
func ( *ServeMux) ( *Task) ( Handler,  string) {
	.mu.RLock()
	defer .mu.RUnlock()

	,  = .match(.Type())
	if  == nil {
		,  = NotFoundHandler(), ""
	}
	for  := len(.mws) - 1;  >= 0; -- {
		 = .mws[]()
	}
	return , 
}

// Find a handler on a handler map given a typename string.
// Most-specific (longest) pattern wins.
func ( *ServeMux) ( string) ( Handler,  string) {
	// Check for exact match first.
	,  := .m[]
	if  {
		return .h, .pattern
	}

	// Check for longest valid match.
	// mux.es contains all patterns from longest to shortest.
	for ,  := range .es {
		if strings.HasPrefix(, .pattern) {
			return .h, .pattern
		}
	}
	return nil, ""

}

// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func ( *ServeMux) ( string,  Handler) {
	.mu.Lock()
	defer .mu.Unlock()

	if strings.TrimSpace() == "" {
		panic("asynq: invalid pattern")
	}
	if  == nil {
		panic("asynq: nil handler")
	}
	if ,  := .m[];  {
		panic("asynq: multiple registrations for " + )
	}

	if .m == nil {
		.m = make(map[string]muxEntry)
	}
	 := muxEntry{h: , pattern: }
	.m[] = 
	.es = appendSorted(.es, )
}

func appendSorted( []muxEntry,  muxEntry) []muxEntry {
	 := len()
	 := sort.Search(, func( int) bool {
		return len([].pattern) < len(.pattern)
	})
	if  ==  {
		return append(, )
	}
	// we now know that i points at where we want to insert.
	 = append(, muxEntry{}) // try to grow the slice in place, any entry works.
	copy([+1:], [:])      // shift shorter entries down.
	[] = 
	return 
}

// HandleFunc registers the handler function for the given pattern.
func ( *ServeMux) ( string,  func(context.Context, *Task) error) {
	if  == nil {
		panic("asynq: nil handler")
	}
	.Handle(, HandlerFunc())
}

// Use appends a MiddlewareFunc to the chain.
// Middlewares are executed in the order that they are applied to the ServeMux.
func ( *ServeMux) ( ...MiddlewareFunc) {
	.mu.Lock()
	defer .mu.Unlock()
	for ,  := range  {
		.mws = append(.mws, )
	}
}

// NotFound returns an error indicating that the handler was not found for the given task.
func ( context.Context,  *Task) error {
	return fmt.Errorf("handler not found for task %q", .Type())
}

// NotFoundHandler returns a simple task handler that returns a ``not found`` error.
func () Handler { return HandlerFunc(NotFound) }