func (p *Pipeline) EnableTrace() {
	utils.EnableVerbose()
}
EnableTrace enable trace log
TODO: refactoring required, because logging enabled for all pipelines, not for selected
package objects
import (
	"fmt"
	"reflect"
	"sort"
	"sync"
	utils "github.com/soldatov-s/go-gpss/internal"
)
type Pipeline struct {
	Name      string               
	objects   map[string]IBaseObj  
	lstObject []IBaseObj           
	ModelTime int                  
	Done      chan struct{}        
	SimTime   int                  
	id        int                  
	doneHndl  []func(p *Pipeline)  
}
type IPipeline interface {
	AddObject(obj IBaseObj) IBaseObj
}
func NewPipeline(name string, doneHndl ...func(p *Pipeline)) *Pipeline {
	return &Pipeline{
		objects:  make(map[string]IBaseObj),
		Name:     name,
		Done:     make(chan struct{}),
		doneHndl: doneHndl,
	}
}
func (p *Pipeline) AddObject(obj ...IBaseObj) *Pipeline {
	if p.lstObject != nil {
		for _, item := range p.lstObject {
			item.SetDst(obj...)
		}
	}
	for _, item := range obj {
		item.SetPipeline(p)
		item.SetID(len(p.objects))
		p.objects[item.GetName()] = item
	}
	p.lstObject = obj
	return p
}
func (p *Pipeline) Loop(objName string) *Pipeline {
	for _, item := range p.lstObject {
		item.SetDst(p.GetObjByName(objName))
		fmt.Println(item.GetName())
	}
	return p
}
func (p *Pipeline) LoopByObj(obj IBaseObj) *Pipeline {
	for _, item := range p.lstObject {
		item.SetDst(obj)
		fmt.Println(obj.GetName())
	}
	return p
}
func (p *Pipeline) Append(obj IBaseObj, dst ...IBaseObj) {
	p.AppendISlice(obj, dst)
}
func (p *Pipeline) AppendMultiple(obj []IBaseObj, dst ...IBaseObj) {
	for _, o := range obj {
		p.AppendISlice(o, dst)
	}
}
func (p *Pipeline) AppendISlice(obj IBaseObj, dst []IBaseObj) {
	obj.SetDst(dst...)
	obj.SetPipeline(p)
	obj.SetID(len(p.objects))
	p.objects[obj.GetName()] = obj
}
func (p *Pipeline) Delete(obj IBaseObj) {
	delete(p.objects, obj.GetName())
}
func (p *Pipeline) PrintObjects() {
	keys := make([]string, 0, len(p.objects))
	for k := range p.objects {
		keys = append(keys, k)
	}
	fmt.Println("Pipeline ", p.Name)
	for _, k := range keys {
		fmt.Println("Key:", k, "Value:", reflect.TypeOf(p.objects[k]))
	}
}
func (p *Pipeline) Start(value int) {
	var wg sync.WaitGroup
	p.SimTime = value
	go func() {
		for {
			select {
			case <-p.Done:
				for _, f := range p.doneHndl {
					f(p)
				}
				return
			default:
				utils.Log.Trace.Println("ModelTime ", p.ModelTime)
				wg.Add(len(p.objects))
				for _, o := range p.objects {
					o.HandleTransacts(&wg)
				}
				wg.Wait()
				p.ModelTime++
				if p.ModelTime == value {
					p.Stop()
				}
			}
		}
	}()
}
func (p *Pipeline) Stop() {
	close(p.Done)
}
func (p *Pipeline) Report() {
	fmt.Println("Pipeline name \"", p.Name, "\"")
	fmt.Println("Simulation time", p.ModelTime)
	sortedObjects := make([]IBaseObj, 0, len(p.objects))
	for _, v := range p.objects {
		sortedObjects = append(sortedObjects, v)
	}
	id := func(p1, p2 IBaseObj) bool {
		return p1.GetID() < p2.GetID()
	}
	By(id).Sort(sortedObjects)
	for _, v := range sortedObjects {
		v.Report()
	}
}
func (p *Pipeline) GetObjByName(name string) IBaseObj {
	return p.objects[name]
}
type By func(p1, p2 IBaseObj) bool
func (by By) Sort(objects []IBaseObj) {
	objs := &objectSorter{
		objects: objects,
		by:      by,
	}
	sort.Sort(objs)
}
type objectSorter struct {
	objects []IBaseObj
	by      By
}
func (s *objectSorter) Len() int {
	return len(s.objects)
}
func (s *objectSorter) Swap(i, j int) {
	s.objects[i], s.objects[j] = s.objects[j], s.objects[i]
}
func (s *objectSorter) Less(i, j int) bool {
	return s.by(s.objects[i], s.objects[j])
}
func (p *Pipeline) NewID() int {
	p.id++
	return p.id
}