github.com/Schaudge/hts@v0.0.0-20240223063651-737b4d69d68c/sam/program.go (about)

     1  // Copyright ©2012 The bíogo Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sam
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  )
    12  
    13  // Program represents a SAM program.
    14  type Program struct {
    15  	owner     *Header
    16  	id        int32
    17  	uid       string
    18  	previous  string
    19  	name      string
    20  	command   string
    21  	version   string
    22  	otherTags []tagPair
    23  }
    24  
    25  // NewProgram returns a Program with the given unique ID, name, command,
    26  // previous program ID in the pipeline and version.
    27  func NewProgram(uid, name, command, prev, v string) *Program {
    28  	return &Program{
    29  		id:       -1,
    30  		uid:      uid,
    31  		previous: prev,
    32  		name:     name,
    33  		command:  command,
    34  		version:  v,
    35  	}
    36  }
    37  
    38  // ID returns the header ID for the Program.
    39  func (p *Program) ID() int {
    40  	if p == nil {
    41  		return -1
    42  	}
    43  	return int(p.id)
    44  }
    45  
    46  // UID returns the unique program ID for the program.
    47  func (p *Program) UID() string {
    48  	if p == nil {
    49  		return ""
    50  	}
    51  	return p.uid
    52  }
    53  
    54  // SetUID sets the unique program ID to uid.
    55  func (r *Program) SetUID(uid string) error {
    56  	if r.owner != nil {
    57  		id, exists := r.owner.seenProgs[uid]
    58  		if exists {
    59  			if id != r.id {
    60  				return errors.New("sam: uid exists")
    61  			}
    62  			return nil
    63  		}
    64  		delete(r.owner.seenProgs, r.uid)
    65  		r.owner.seenProgs[uid] = r.id
    66  	}
    67  	r.uid = uid
    68  	return nil
    69  }
    70  
    71  // Name returns the program's name.
    72  func (p *Program) Name() string {
    73  	if p == nil {
    74  		return ""
    75  	}
    76  	return p.name
    77  }
    78  
    79  // Command returns the program's command line.
    80  func (p *Program) Command() string {
    81  	if p == nil {
    82  		return ""
    83  	}
    84  	return p.command
    85  }
    86  
    87  // Previous returns the unique ID for the previous program in the pipeline.
    88  func (p *Program) Previous() string {
    89  	if p == nil {
    90  		return ""
    91  	}
    92  	return p.previous
    93  }
    94  
    95  // Version returns the version of the program.
    96  func (p *Program) Version() string {
    97  	if p == nil {
    98  		return ""
    99  	}
   100  	return p.version
   101  }
   102  
   103  // Clone returns a deep copy of the Program.
   104  func (p *Program) Clone() *Program {
   105  	if p == nil {
   106  		return nil
   107  	}
   108  	cp := *p
   109  	if len(cp.otherTags) != 0 {
   110  		cp.otherTags = make([]tagPair, len(cp.otherTags))
   111  	}
   112  	copy(cp.otherTags, p.otherTags)
   113  	cp.id = -1
   114  	cp.owner = nil
   115  	return &cp
   116  }
   117  
   118  // Tags applies the function fn to each of the tag-value pairs of the Program.
   119  // The function fn must not add or delete tags held by the receiver during
   120  // iteration.
   121  func (p *Program) Tags(fn func(t Tag, value string)) {
   122  	if fn == nil {
   123  		return
   124  	}
   125  	fn(idTag, p.UID())
   126  	if p.name != "" {
   127  		fn(programNameTag, p.name)
   128  	}
   129  	if p.command != "" {
   130  		fn(commandLineTag, p.command)
   131  	}
   132  	if p.previous != "" {
   133  		fn(previousProgTag, p.previous)
   134  	}
   135  	if p.version != "" {
   136  		fn(versionTag, p.version)
   137  	}
   138  	for _, tp := range p.otherTags {
   139  		fn(tp.tag, tp.value)
   140  	}
   141  }
   142  
   143  // Get returns the string representation of the value associated with the
   144  // given program line tag. If the tag is not present the empty string is returned.
   145  func (p *Program) Get(t Tag) string {
   146  	switch t {
   147  	case idTag:
   148  		return p.UID()
   149  	case programNameTag:
   150  		return p.Name()
   151  	case commandLineTag:
   152  		return p.Command()
   153  	case previousProgTag:
   154  		return p.Previous()
   155  	case versionTag:
   156  		return p.Version()
   157  	}
   158  	for _, tp := range p.otherTags {
   159  		if t == tp.tag {
   160  			return tp.value
   161  		}
   162  	}
   163  	return ""
   164  }
   165  
   166  // Set sets the value associated with the given program line tag to the specified
   167  // value. If value is the empty string and the tag may be absent, it is deleted.
   168  func (p *Program) Set(t Tag, value string) error {
   169  	switch t {
   170  	case idTag:
   171  		if value == "" {
   172  			return errDupProgram
   173  		}
   174  	case programNameTag:
   175  		p.name = value
   176  	case commandLineTag:
   177  		p.command = value
   178  	case previousProgTag:
   179  		p.previous = value
   180  	case versionTag:
   181  		p.version = value
   182  	default:
   183  		if value == "" {
   184  			for i, tp := range p.otherTags {
   185  				if t == tp.tag {
   186  					copy(p.otherTags[i:], p.otherTags[i+1:])
   187  					p.otherTags = p.otherTags[:len(p.otherTags)-1]
   188  					return nil
   189  				}
   190  			}
   191  		} else {
   192  			for i, tp := range p.otherTags {
   193  				if t == tp.tag {
   194  					p.otherTags[i].value = value
   195  					return nil
   196  				}
   197  			}
   198  			p.otherTags = append(p.otherTags, tagPair{tag: t, value: value})
   199  		}
   200  	}
   201  	return nil
   202  }
   203  
   204  // String returns a string representation of the program according to the
   205  // SAM specification section 1.3,
   206  func (p *Program) String() string {
   207  	var buf bytes.Buffer
   208  	fmt.Fprintf(&buf, "@PG\tID:%s", p.uid)
   209  	if p.name != "" {
   210  		fmt.Fprintf(&buf, "\tPN:%s", p.name)
   211  	}
   212  	if p.command != "" {
   213  		fmt.Fprintf(&buf, "\tCL:%s", p.command)
   214  	}
   215  	if p.previous != "" {
   216  		fmt.Fprintf(&buf, "\tPP:%s", p.previous)
   217  	}
   218  	if p.version != "" {
   219  		fmt.Fprintf(&buf, "\tVN:%s", p.version)
   220  	}
   221  	for _, tp := range p.otherTags {
   222  		fmt.Fprintf(&buf, "\t%s:%s", tp.tag, tp.value)
   223  	}
   224  	return buf.String()
   225  }