package jen

import (
	
	
	
	
)

// Group represents a list of Code items, separated by tokens with an optional
// open and close token.
type Group struct {
	name      string
	items     []Code
	open      string
	close     string
	separator string
	multi     bool
}

func ( *Group) ( *File) bool {
	if  == nil {
		return true
	}
	if .open != "" || .close != "" {
		return false
	}
	return .isNullItems()
}

func ( *Group) ( *File) bool {
	for ,  := range .items {
		if !.isNull() {
			return false
		}
	}
	return true
}

func ( *Group) ( *File,  io.Writer,  *Statement) error {
	if .name == "types" && .isNullItems() {
		// Special case for types - if all items are null, don't render the open/close tokens.
		return nil
	}
	if .name == "block" &&  != nil {
		// Special CaseBlock format for then the previous item in the statement
		// is a Case group or the default keyword.
		 := .previous()
		,  := .(*Group)
		,  := .(token)
		if  && .name == "case" ||  && .content == "default" {
			.open = ""
			.close = ""
		}
	}
	if .open != "" {
		if ,  := .Write([]byte(.open));  != nil {
			return 
		}
	}
	,  := .renderItems(, )
	if  != nil {
		return 
	}
	if ! && .multi && .close != "" {
		// For multi-line blocks with a closing token, we insert a new line after the last item (but
		// not if all items were null). This is to ensure that if the statement finishes with a comment,
		// the closing token is not commented out.
		 := "\n"
		if .separator == "," {
			// We also insert add trailing comma if the separator was ",".
			 = ",\n"
		}
		if ,  := .Write([]byte());  != nil {
			return 
		}
	}
	if .close != "" {
		if ,  := .Write([]byte(.close));  != nil {
			return 
		}
	}
	return nil
}

func ( *Group) ( *File,  io.Writer) ( bool,  error) {
	 := true
	for ,  := range .items {
		if ,  := .(token);  && .typ == packageToken {
			// Special case for package tokens in Qual groups - for dot-imports, the package token
			// will be null, so will not render and will not be registered in the imports block.
			// This ensures all packageTokens that are rendered are registered.
			.register(.content.(string))
		}
		if  == nil || .isNull() {
			// Null() token produces no output but also
			// no separator. Empty() token products no
			// output but adds a separator.
			continue
		}
		if .name == "values" {
			if ,  := .(Dict);  && len(.items) > 1 {
				panic("Error in Values: if Dict is used, must be one item only")
			}
		}
		if ! && .separator != "" {
			// The separator token is added before each non-null item, but not before the first item.
			if ,  := .Write([]byte(.separator));  != nil {
				return false, 
			}
		}
		if .multi {
			// For multi-line blocks, we insert a new line before each non-null item.
			if ,  := .Write([]byte("\n"));  != nil {
				return false, 
			}
		}
		if  := .render(, , nil);  != nil {
			return false, 
		}
		 = false
	}
	return , nil
}

// Render renders the Group to the provided writer.
func ( *Group) ( io.Writer) error {
	return .RenderWithFile(, NewFile(""))
}

// GoString renders the Group for testing. Any error will cause a panic.
func ( *Group) () string {
	 := bytes.Buffer{}
	if  := .Render(&);  != nil {
		panic()
	}
	return .String()
}

// RenderWithFile renders the Group to the provided writer, using imports from the provided file.
func ( *Group) ( io.Writer,  *File) error {
	 := &bytes.Buffer{}
	if  := .render(, , nil);  != nil {
		return 
	}
	,  := format.Source(.Bytes())
	if  != nil {
		return fmt.Errorf("Error %s while formatting source:\n%s", , .String())
	}
	if ,  := .Write();  != nil {
		return 
	}
	return nil
}