package sourcemap

import (
	
	
	
	
	
)

type sourceMap struct {
	Version        int               `json:"version"`
	File           string            `json:"file"`
	SourceRoot     string            `json:"sourceRoot"`
	Sources        []string          `json:"sources"`
	SourcesContent []string          `json:"sourcesContent"`
	Names          []json.RawMessage `json:"names,string"`
	Mappings       string            `json:"mappings"`

	mappings []mapping
}

type v3 struct {
	sourceMap
	Sections []section `json:"sections"`
}

func ( *sourceMap) ( string) error {
	if  := checkVersion(.Version);  != nil {
		return 
	}

	var  *url.URL
	if .SourceRoot != "" {
		,  := url.Parse(.SourceRoot)
		if  != nil {
			return 
		}
		if .IsAbs() {
			 = 
		}
	} else if  != "" {
		,  := url.Parse()
		if  != nil {
			return 
		}
		if .IsAbs() {
			.Path = path.Dir(.Path)
			 = 
		}
	}

	for ,  := range .Sources {
		.Sources[] = .absSource(, )
	}

	,  := parseMappings(.Mappings)
	if  != nil {
		return 
	}

	.mappings = 
	// Free memory.
	.Mappings = ""

	return nil
}

func ( *sourceMap) ( *url.URL,  string) string {
	if path.IsAbs() {
		return 
	}

	if ,  := url.Parse();  == nil && .IsAbs() {
		return 
	}

	if  != nil {
		 := *
		.Path = path.Join(.Path, )
		return .String()
	}

	if .SourceRoot != "" {
		return path.Join(.SourceRoot, )
	}

	return 
}

func ( *sourceMap) ( int) string {
	if  >= len(.Names) {
		return ""
	}

	 := .Names[]
	if len() == 0 {
		return ""
	}

	if [0] == '"' && [len()-1] == '"' {
		var  string
		if  := json.Unmarshal(, &);  == nil {
			return 
		}
	}

	return string()
}

type section struct {
	Offset struct {
		Line   int `json:"line"`
		Column int `json:"column"`
	} `json:"offset"`
	Map *sourceMap `json:"map"`
}

type Consumer struct {
	sourcemapURL string
	file         string
	sections     []section
}

func ( string,  []byte) (*Consumer, error) {
	 := new(v3)
	 := json.Unmarshal(, )
	if  != nil {
		return nil, 
	}

	if  := checkVersion(.Version);  != nil {
		return nil, 
	}

	if len(.Sections) == 0 {
		.Sections = append(.Sections, section{
			Map: &.sourceMap,
		})
	}

	for ,  := range .Sections {
		 := .Map.parse()
		if  != nil {
			return nil, 
		}
	}

	reverse(.Sections)
	return &Consumer{
		sourcemapURL: ,
		file:         .File,
		sections:     .Sections,
	}, nil
}

func ( *Consumer) () string {
	return .sourcemapURL
}

// File returns an optional name of the generated code
// that this source map is associated with.
func ( *Consumer) () string {
	return .file
}

// Source returns the original source, name, line, and column information
// for the generated source's line and column positions.
func ( *Consumer) (
	,  int,
) (,  string, ,  int,  bool) {
	for  := range .sections {
		 := &.sections[]
		if .Offset.Line <  ||
			(.Offset.Line+1 ==  && .Offset.Column <= ) {
			 -= .Offset.Line
			 -= .Offset.Column
			return .source(.Map, , )
		}
	}
	return
}

func ( *Consumer) (
	 *sourceMap, ,  int,
) (,  string, ,  int,  bool) {
	if len(.mappings) == 0 {
		return
	}

	 := sort.Search(len(.mappings), func( int) bool {
		 := &.mappings[]
		if int(.genLine) ==  {
			return int(.genColumn) >= 
		}
		return int(.genLine) >= 
	})

	var  *mapping
	// Mapping not found
	if  == len(.mappings) {
		// lets see if the line is correct but the column is bigger
		 = &.mappings[-1]
		if int(.genLine) !=  {
			return
		}
	} else {
		 = &.mappings[]

		// Fuzzy match.
		if int(.genLine) >  || int(.genColumn) >  {
			if  == 0 {
				return
			}
			 = &.mappings[-1]
		}
	}

	if .sourcesInd >= 0 {
		 = .Sources[.sourcesInd]
	}
	if .namesInd >= 0 {
		 = .name(int(.namesInd))
	}
	 = int(.sourceLine)
	 = int(.sourceColumn)
	 = true
	return
}

// SourceContent returns the original source content for the source.
func ( *Consumer) ( string) string {
	for  := range .sections {
		 := &.sections[]
		for ,  := range .Map.Sources {
			if  ==  {
				if  < len(.Map.SourcesContent) {
					return .Map.SourcesContent[]
				}
				break
			}
		}
	}
	return ""
}

func checkVersion( int) error {
	if  == 3 ||  == 0 {
		return nil
	}
	return fmt.Errorf(
		"sourcemap: got version=%d, but only 3rd version is supported",
		,
	)
}

func reverse( []section) {
	 := len() - 1
	for  := 0;  < len()/2; ++ {
		[], [-] = [-], []
	}
}