<commit_before>// Package: fileLogger
// File: fileLogger.go
// Created by: mint(mint.zhao.chiu@gmail.com)_aiwuTech
// Useage:
// DATE: 14-8-23 17:20
package fileLogger

import (
	"log"
	"os"
	"strconv"
	"sync"
	"time"
)

const (
	DATEFORMAT         = "2006-01-02"
	DEFAULT_FILE_COUNT = 10
	DEFAULT_FILE_SIZE  = 50
	DEFAULT_FILE_UNIT  = MB
	DEFAULT_LOG_SCAN   = 300
	DEFAULT_LOG_SEQ    = 5000
	DEFAULT_LOG_LEVEL  = TRACE
)

type UNIT int64

const (
	_       = iota
	KB UNIT = 1 << (iota * 10)
	MB
	GB
	TB
)

type SplitType byte

const (
	SplitType_Size SplitType = iota
	SplitType_Daily
)

type LEVEL byte

const (
	TRACE LEVEL = iota
	INFO
	WARN
	ERROR
	OFF
)

type FileLogger struct {
	splitType SplitType
	mu        *sync.RWMutex
	fileDir   string
	fileName  string
	suffix    int
	fileCount int
	fileSize  int64
	prefix    string

	date *time.Time

	logFile *os.File
	lg      *log.Logger

	logScan int64

	logChan chan string

	logLevel LEVEL
	logConsole bool
}

// NewDefaultLogger return a logger split by fileSize by default
func NewDefaultLogger(fileDir, fileName string) *FileLogger {
	return NewSizeLogger(fileDir, fileName, "",
		DEFAULT_FILE_COUNT, DEFAULT_FILE_SIZE, DEFAULT_FILE_UNIT, DEFAULT_LOG_SCAN, DEFAULT_LOG_SEQ)
}

// NewSizeLogger return a logger split by fileSize
// Parameters:
// 		file directory
// 		file name
// 		log's prefix
// 		fileCount holds maxCount of bak file
//		fileSize holds each of bak file's size
// 		unit stands for kb, mb, gb, tb
//		logScan after a logScan time will check fileLogger isMustSplit, default is 300s
func NewSizeLogger(fileDir, fileName, prefix string, fileCount int, fileSize int64, unit UNIT,
	logScan int64, logSeq int) *FileLogger {
	sizeLogger := &FileLogger{
		splitType: SplitType_Size,
		mu:        new(sync.RWMutex),
		fileDir:   fileDir,
		fileName:  fileName,
		fileCount: fileCount,
		fileSize:  fileSize * int64(unit),
		prefix:    prefix,
		logScan:   logScan,
		logChan:   make(chan string, logSeq),
		logLevel:  DEFAULT_LOG_LEVEL,
		logConsole: false,
	}

	sizeLogger.initLogger()

	return sizeLogger
}

// NewDailyLogger return a logger split by daily
// Parameters:
// 		file directory
// 		file name
// 		log's prefix
func NewDailyLogger(fileDir, fileName, prefix string, logScan int64, logSeq int) *FileLogger {
	dailyLogger := &FileLogger{
		splitType: SplitType_Daily,
		mu:        new(sync.RWMutex),
		fileDir:   fileDir,
		fileName:  fileName,
		prefix:    prefix,
		logScan:   logScan,
		logChan:   make(chan string, logSeq),
		logLevel:  DEFAULT_LOG_LEVEL,
		logConsole: false,
	}

	dailyLogger.initLogger()

	return dailyLogger
}

func (f *FileLogger) initLogger() {

	switch f.splitType {
	case SplitType_Size:
		f.initLoggerBySize()
	case SplitType_Daily:
		f.initLoggerByDaily()
	}

}

// init filelogger split by fileSize
func (f *FileLogger) initLoggerBySize() {

	f.mu.Lock()
	defer f.mu.Unlock()

	logFile := joinFilePath(f.fileDir, f.fileName)
	for i := 1; i <= f.fileCount; i++ {
		if isExist(logFile + "." + strconv.Itoa(i)) {
			f.suffix = i
		}

		break
	}

	if !f.isMustSplit() {
		if !isExist(f.fileDir) {
			os.Mkdir(f.fileDir, 0755)
		}
		f.logFile, _ = os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
		f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)
	} else {
		f.split()
	}

	go f.logWriter()
	go f.fileMonitor()
}

// init fileLogger split by daily
func (f *FileLogger) initLoggerByDaily() {

	t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))

	f.date = &t
	f.mu.Lock()
	defer f.mu.Unlock()

	logFile := joinFilePath(f.fileDir, f.fileName)
	if !f.isMustSplit() {
		if !isExist(f.fileDir) {
			os.Mkdir(f.fileDir, 0755)
		}
		f.logFile, _ = os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
		f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)
	} else {
		f.split()
	}

	go f.logWriter()
	go f.fileMonitor()
}

// used for determine the fileLogger f is time to split.
// size: once the current fileLogger's fileSize >= config.fileSize need to split
// daily: once the current fileLogger stands for yesterday need to split
func (f *FileLogger) isMustSplit() bool {

	switch f.splitType {
	case SplitType_Size:
		logFile := joinFilePath(f.fileDir, f.fileName)
		if f.fileCount > 1 {
			if fileSize(logFile) >= f.fileSize {
				return true
			}
		}
	case SplitType_Daily:
		t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
		if t.After(*f.date) {
			return true
		}
	}

	return false
}

// Split fileLogger
func (f *FileLogger) split() {

	logFile := joinFilePath(f.fileDir, f.fileName)

	switch f.splitType {
	case SplitType_Size:
		f.suffix = int(f.suffix%f.fileCount + 1)
		if f.logFile != nil {
			f.logFile.Close()
		}

		logFileBak := logFile + "." + strconv.Itoa(f.suffix)
		if isExist(logFileBak) {
			os.Remove(logFileBak)
		}
		os.Rename(logFile, logFileBak)

		f.logFile, _ = os.Create(logFile)
		f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)

	case SplitType_Daily:
		logFileBak := logFile + "." + f.date.Format(DATEFORMAT)
		if !isExist(logFileBak) && f.isMustSplit() {
			if f.logFile != nil {
				f.logFile.Close()
			}

			err := os.Rename(logFile, logFileBak)
			if err != nil {
				f.lg.Printf("FileLogger rename error: %v", err.Error())
			}

			t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
			f.date = &t
			f.logFile, _ = os.Create(logFile)
			f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)
		}
	}
}

// After some interval time, goto check the current fileLogger's size or date
func (f *FileLogger) fileMonitor() {
	defer func() {
		if err := recover(); err != nil {
			f.lg.Printf("FileLogger's FileMonitor() catch panic: %v\n", err)
		}
	}()

	//TODO  load logScan interval from config file
	logScan := DEFAULT_LOG_SCAN

	timer := time.NewTicker(time.Duration(logScan) * time.Second)
	for {
		select {
		case <-timer.C:
			f.fileCheck()
		}
	}
}

// If the current fileLogger need to split, just split
func (f *FileLogger) fileCheck() {
	defer func() {
		if err := recover(); err != nil {
			f.lg.Printf("FileLogger's FileCheck() catch panic: %v\n", err)
		}
	}()

	if f.isMustSplit() {
		f.mu.Lock()
		defer f.mu.Unlock()

		f.split()
	}
}
<commit_msg>add close()<commit_after>// Package: fileLogger
// File: fileLogger.go
// Created by: mint(mint.zhao.chiu@gmail.com)_aiwuTech
// Useage:
// DATE: 14-8-23 17:20
package fileLogger

import (
	"log"
	"os"
	"strconv"
	"sync"
	"time"
)

const (
	DATEFORMAT         = "2006-01-02"
	DEFAULT_FILE_COUNT = 10
	DEFAULT_FILE_SIZE  = 50
	DEFAULT_FILE_UNIT  = MB
	DEFAULT_LOG_SCAN   = 300
	DEFAULT_LOG_SEQ    = 5000
	DEFAULT_LOG_LEVEL  = TRACE
)

type UNIT int64

const (
	_       = iota
	KB UNIT = 1 << (iota * 10)
	MB
	GB
	TB
)

type SplitType byte

const (
	SplitType_Size SplitType = iota
	SplitType_Daily
)

type LEVEL byte

const (
	TRACE LEVEL = iota
	INFO
	WARN
	ERROR
	OFF
)

type FileLogger struct {
	splitType SplitType
	mu        *sync.RWMutex
	fileDir   string
	fileName  string
	suffix    int
	fileCount int
	fileSize  int64
	prefix    string

	date *time.Time

	logFile *os.File
	lg      *log.Logger

	logScan int64

	logChan chan string

	logLevel LEVEL
	logConsole bool
}

// NewDefaultLogger return a logger split by fileSize by default
func NewDefaultLogger(fileDir, fileName string) *FileLogger {
	return NewSizeLogger(fileDir, fileName, "",
		DEFAULT_FILE_COUNT, DEFAULT_FILE_SIZE, DEFAULT_FILE_UNIT, DEFAULT_LOG_SCAN, DEFAULT_LOG_SEQ)
}

// NewSizeLogger return a logger split by fileSize
// Parameters:
// 		file directory
// 		file name
// 		log's prefix
// 		fileCount holds maxCount of bak file
//		fileSize holds each of bak file's size
// 		unit stands for kb, mb, gb, tb
//		logScan after a logScan time will check fileLogger isMustSplit, default is 300s
func NewSizeLogger(fileDir, fileName, prefix string, fileCount int, fileSize int64, unit UNIT,
	logScan int64, logSeq int) *FileLogger {
	sizeLogger := &FileLogger{
		splitType: SplitType_Size,
		mu:        new(sync.RWMutex),
		fileDir:   fileDir,
		fileName:  fileName,
		fileCount: fileCount,
		fileSize:  fileSize * int64(unit),
		prefix:    prefix,
		logScan:   logScan,
		logChan:   make(chan string, logSeq),
		logLevel:  DEFAULT_LOG_LEVEL,
		logConsole: false,
	}

	sizeLogger.initLogger()

	return sizeLogger
}

// NewDailyLogger return a logger split by daily
// Parameters:
// 		file directory
// 		file name
// 		log's prefix
func NewDailyLogger(fileDir, fileName, prefix string, logScan int64, logSeq int) *FileLogger {
	dailyLogger := &FileLogger{
		splitType: SplitType_Daily,
		mu:        new(sync.RWMutex),
		fileDir:   fileDir,
		fileName:  fileName,
		prefix:    prefix,
		logScan:   logScan,
		logChan:   make(chan string, logSeq),
		logLevel:  DEFAULT_LOG_LEVEL,
		logConsole: false,
	}

	dailyLogger.initLogger()

	return dailyLogger
}

func (f *FileLogger) initLogger() {

	switch f.splitType {
	case SplitType_Size:
		f.initLoggerBySize()
	case SplitType_Daily:
		f.initLoggerByDaily()
	}

}

// init filelogger split by fileSize
func (f *FileLogger) initLoggerBySize() {

	f.mu.Lock()
	defer f.mu.Unlock()

	logFile := joinFilePath(f.fileDir, f.fileName)
	for i := 1; i <= f.fileCount; i++ {
		if isExist(logFile + "." + strconv.Itoa(i)) {
			f.suffix = i
		}

		break
	}

	if !f.isMustSplit() {
		if !isExist(f.fileDir) {
			os.Mkdir(f.fileDir, 0755)
		}
		f.logFile, _ = os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
		f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)
	} else {
		f.split()
	}

	go f.logWriter()
	go f.fileMonitor()
}

// init fileLogger split by daily
func (f *FileLogger) initLoggerByDaily() {

	t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))

	f.date = &t
	f.mu.Lock()
	defer f.mu.Unlock()

	logFile := joinFilePath(f.fileDir, f.fileName)
	if !f.isMustSplit() {
		if !isExist(f.fileDir) {
			os.Mkdir(f.fileDir, 0755)
		}
		f.logFile, _ = os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
		f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)
	} else {
		f.split()
	}

	go f.logWriter()
	go f.fileMonitor()
}

// used for determine the fileLogger f is time to split.
// size: once the current fileLogger's fileSize >= config.fileSize need to split
// daily: once the current fileLogger stands for yesterday need to split
func (f *FileLogger) isMustSplit() bool {

	switch f.splitType {
	case SplitType_Size:
		logFile := joinFilePath(f.fileDir, f.fileName)
		if f.fileCount > 1 {
			if fileSize(logFile) >= f.fileSize {
				return true
			}
		}
	case SplitType_Daily:
		t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
		if t.After(*f.date) {
			return true
		}
	}

	return false
}

// Split fileLogger
func (f *FileLogger) split() {

	logFile := joinFilePath(f.fileDir, f.fileName)

	switch f.splitType {
	case SplitType_Size:
		f.suffix = int(f.suffix%f.fileCount + 1)
		if f.logFile != nil {
			f.logFile.Close()
		}

		logFileBak := logFile + "." + strconv.Itoa(f.suffix)
		if isExist(logFileBak) {
			os.Remove(logFileBak)
		}
		os.Rename(logFile, logFileBak)

		f.logFile, _ = os.Create(logFile)
		f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)

	case SplitType_Daily:
		logFileBak := logFile + "." + f.date.Format(DATEFORMAT)
		if !isExist(logFileBak) && f.isMustSplit() {
			if f.logFile != nil {
				f.logFile.Close()
			}

			err := os.Rename(logFile, logFileBak)
			if err != nil {
				f.lg.Printf("FileLogger rename error: %v", err.Error())
			}

			t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
			f.date = &t
			f.logFile, _ = os.Create(logFile)
			f.lg = log.New(f.logFile, f.prefix, log.LstdFlags|log.Lmicroseconds)
		}
	}
}

// After some interval time, goto check the current fileLogger's size or date
func (f *FileLogger) fileMonitor() {
	defer func() {
		if err := recover(); err != nil {
			f.lg.Printf("FileLogger's FileMonitor() catch panic: %v\n", err)
		}
	}()

	//TODO  load logScan interval from config file
	logScan := DEFAULT_LOG_SCAN

	timer := time.NewTicker(time.Duration(logScan) * time.Second)
	for {
		select {
		case <-timer.C:
			f.fileCheck()
		}
	}
}

// If the current fileLogger need to split, just split
func (f *FileLogger) fileCheck() {
	defer func() {
		if err := recover(); err != nil {
			f.lg.Printf("FileLogger's FileCheck() catch panic: %v\n", err)
		}
	}()

	if f.isMustSplit() {
		f.mu.Lock()
		defer f.mu.Unlock()

		f.split()
	}
}

// passive to close fileLogger
func (f *FileLogger) Close() error {

	f.logChan.Close()
	f.lg = nil

	return f.logFile.Close()
}
<|endoftext|>


<commit_before>package files

import (
	"io"
	"os"
	"path/filepath"
)

// Copy copies a file to a given destination. It makes sur parent folders are
// created on the way. Use `-` to copy to stdout.
func Copy(src, dst string) error {
	if dst != "-" {
		if err := MkdirAll(filepath.Dir(dst)); err != nil {
			return err
		}
	}

	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()

	var out io.Writer
	if dst != "-" {
		destOut, err := os.Create(dst)
		if err != nil {
			return err
		}
		defer destOut.Close()

		out = destOut
	} else {
		out = os.Stdout
	}

	_, err = io.Copy(out, in)
	return err
}

func CopyFrom(dst string, mode os.FileMode, reader io.Reader) error {
	if err := MkdirAll(filepath.Dir(dst)); err != nil {
		return err
	}

	file, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = io.Copy(file, reader)
	return err
}
<commit_msg>Support output to stdout for any action<commit_after>package files

import (
	"io"
	"os"
	"path/filepath"
)

// Copy copies a file to a given destination. It makes sur parent folders are
// created on the way. Use `-` to copy to stdout.
func Copy(src, dst string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()

	return CopyFrom(dst, 0666, in)
}

func CopyFrom(dst string, mode os.FileMode, reader io.Reader) error {
	var out io.Writer
	if dst == "-" {
		out = os.Stdout
	} else {
		if err := MkdirAll(filepath.Dir(dst)); err != nil {
			return err
		}

		file, err := os.OpenFile(dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode)
		if err != nil {
			return err
		}
		defer file.Close()

		out = file
	}

	_, err := io.Copy(out, reader)
	return err
}
<|endoftext|>


<commit_before>package assets

import (
	"bytes"
	"net/http"
	"os"
)

// An in-memory asset file system. The file system implements the
// http.FileSystem interface.
type FileSystem struct {
	// A map of directory paths to the files in those directories.
	Dirs map[string][]string

	// A map of file/directory paths to assets.File types.
	Files map[string]*File

	// Whether or not the file data in the file system is stored in gzip
	// compressed form.
	Compressed bool
}

func (f *FileSystem) NewFile(path string, filemode os.FileMode, mtime time.Time, data []byte) *File {
	return &File{
		Path:     path,
		FileMode: filemode,
		Mtime:    mtime,
		Data:     data,

		fs: f,
	}
}

// Implementation of http.FileSystem
func (f *FileSystem) Open(path string) (http.File, error) {
	if fi, ok := f.Files[path]; ok {
		if !fi.IsDir() {
			// Make a copy for reading
			ret := fi
			ret.buf = bytes.NewReader(ret.Data)

			return ret, nil
		}

		return fi, nil
	}

	return nil, os.ErrNotExist
}

func (f *FileSystem) readDir(p string, index int, count int) ([]os.FileInfo, error) {
	if d, ok := f.Dirs[p]; ok {
		maxl := index + count

		if maxl > len(d) {
			maxl = len(d)
		}

		ret := make([]os.FileInfo, 0, maxl-index)

		for i := index; i < maxl; i++ {
			ret = append(ret, f.Files[path.Join(p, d[i])])
		}

		return ret, nil
	}

	return nil, os.ErrNotExist
}
<commit_msg>Remove compressed thingie<commit_after>package assets

import (
	"bytes"
	"net/http"
	"os"
)

// An in-memory asset file system. The file system implements the
// http.FileSystem interface.
type FileSystem struct {
	// A map of directory paths to the files in those directories.
	Dirs map[string][]string

	// A map of file/directory paths to assets.File types.
	Files map[string]*File

}

func (f *FileSystem) NewFile(path string, filemode os.FileMode, mtime time.Time, data []byte) *File {
	return &File{
		Path:     path,
		FileMode: filemode,
		Mtime:    mtime,
		Data:     data,

		fs: f,
	}
}

// Implementation of http.FileSystem
func (f *FileSystem) Open(path string) (http.File, error) {
	if fi, ok := f.Files[path]; ok {
		if !fi.IsDir() {
			// Make a copy for reading
			ret := fi
			ret.buf = bytes.NewReader(ret.Data)

			return ret, nil
		}

		return fi, nil
	}

	return nil, os.ErrNotExist
}

func (f *FileSystem) readDir(p string, index int, count int) ([]os.FileInfo, error) {
	if d, ok := f.Dirs[p]; ok {
		maxl := index + count

		if maxl > len(d) {
			maxl = len(d)
		}

		ret := make([]os.FileInfo, 0, maxl-index)

		for i := index; i < maxl; i++ {
			ret = append(ret, f.Files[path.Join(p, d[i])])
		}

		return ret, nil
	}

	return nil, os.ErrNotExist
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"strings"
)

// blockVisitor walks the AST and extracts the first Block Statement it finds.
// We only use it when we've generated the code ourselves so we know there is only
// one code block to look for
type blockVisitor struct {
	stmts []ast.Stmt
}

func (v *blockVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.BlockStmt:
		v.stmts = n.List
		return nil
	}
	return v
}

// InterfaceVisitor walks the AST and finds interfaces
type InterfaceVisitor struct {
	fset *token.FileSet
	name string
	code string
}

func (i *InterfaceVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.TypeSpec:
		t, ok := n.Type.(*ast.InterfaceType)
		if ok {
			// This is an interface
			if n.Name.Name != i.name {
				return nil
			}
			i.code = i.buildMockForInterface(t)
			return nil
		}
	}
	return i
}

func (i *InterfaceVisitor) buildMockForInterface(t *ast.InterfaceType) string {
	var buf bytes.Buffer

	// Mock Implementation of the interface
	printer.Fprint(&buf, i.fset, buildMockStruct(i.name))
	buf.WriteString("\n\n")

	// Method receiver for our mock interface
	recv := buildMethodReceiver(i.name)

	for _, m := range t.Methods.List {
		t, ok := m.Type.(*ast.FuncType)
		if ok {
			// Names for return values causes problems, so remove them.
			if t.Results != nil {
				removeFieldNames(t.Results)
			}

			// We can have multiple names for a method type if multiple
			// methods are declared with the same signature
			for _, n := range m.Names {
				fd := buildMockMethod(recv, n.Name, t)
				printer.Fprint(&buf, i.fset, fd)
				buf.WriteString("\n\n")
			}
		}
	}
	return buf.String()
}

// removeFieldNames removes names from the FieldList in place.
// This is used to remove names from return values
func removeFieldNames(fl *ast.FieldList) {
	l := []*ast.Field{}
	for _, f := range fl.List {
		if f.Names == nil {
			l = append(l, f)
		} else {
			for range f.Names {
				nf := *f
				nf.Names = nil
				l = append(l, &nf)
			}
		}
	}
	fl.List = l
}

// parseCodeBlock() parses a block of code.
//
// It works by embedding the code in a dummy go file with a function, then
// extracting the AST for the code block we're interested in
func parseCodeBlock(code string) ([]ast.Stmt, error) {
	// Embed the code in a function and add a package
	code = "package dummy\nfunc dummy() {\n" + code + "\n}\n"

	// Parse the code
	fset := token.NewFileSet()
	af, err := parser.ParseFile(fset, "dummy.go", code, 0)
	if err != nil {
		return nil, err
	}

	// Extract the statements we need
	v := &blockVisitor{}
	ast.Walk(v, af)

	return v.stmts, nil
}

func buildMockStruct(name string) *ast.DeclStmt {
	return &ast.DeclStmt{
		Decl: &ast.GenDecl{
			Tok: token.TYPE,
			Specs: []ast.Spec{
				&ast.TypeSpec{
					Name: ast.NewIdent(fmt.Sprintf("Mock%s", name)),
					Type: &ast.StructType{
						Fields: &ast.FieldList{
							List: []*ast.Field{
								{
									Type: &ast.SelectorExpr{
										X:   ast.NewIdent("ut"),
										Sel: ast.NewIdent("CallTracker"),
									},
								},
							},
						},
					},
				},
			},
		},
	}
}

func buildMethodReceiver(name string) *ast.FieldList {
	return &ast.FieldList{
		List: []*ast.Field{
			{
				Names: []*ast.Ident{
					ast.NewIdent("i"),
				},
				Type: &ast.StarExpr{
					X: ast.NewIdent(fmt.Sprintf("Mock%s", name)),
				},
			},
		},
	}
}

/* buildMockMethod builds the AST for the mock method.
The function body needs to look something like:

	r := ut.TrackCall("method", param1, param2)
	return r[0].(int), r[1].(thing)

... except we need to worry about types a little more for the
return values.  So instead we do

	r := ut.TrackCall("method", param1, param2)
	var r_0 int
	var r_1 thing
	if r[0] != nil { r_0 = r[0].(int) }
	if r[1] != nil { r_1 = r[1].(thing) }
	return r_0, r_1

... and we might have an ellipsis parameter so in fact we do

	params := make([]interface{}, 2)
	params[0] = param1
	params[1] = param2
	r := ut.TrackCall("method", params...)
	var r_0 int
	var r_1 thing
	if r[0] != nil { r_0 = r[0].(int) }
	if r[1] != nil { r_1 = r[1].(thing) }
	return r_0, r_1
*/
func buildMockMethod(recv *ast.FieldList, name string, t *ast.FuncType) *ast.FuncDecl {
	stmts := []ast.Stmt{}
	p, err := storeParams(t.Params)
	if err != nil {
		fmt.Printf("Failed to set up call parameters. %v", err)
	}
	stmts = append(stmts, p...)
	p, err = trackCall(t.Results.NumFields(), name)
	if err != nil {
		fmt.Printf("failed to track call. %v", err)
	}
	stmts = append(stmts, p...)

	p, err = declReturnValues(t.Results)
	if err != nil {
		fmt.Printf("failed to declare return values. %v", err)
	}
	stmts = append(stmts, p...)

	p, err = buildReturnStatement(t.Results.NumFields())
	if err != nil {
		fmt.Printf("failed to build return statement. %v", err)
	}
	if p != nil {
		stmts = append(stmts, p...)
	}

	// This is our method declaration
	return &ast.FuncDecl{
		Type: t,
		Name: ast.NewIdent(name),
		Recv: recv,
		Body: &ast.BlockStmt{
			List: stmts,
		},
	}
}

// storeParams handles parameters
//
// Because our parameters may contain an ellipsis we always need to add all the parameters
// to an interface{} array
//
//  params := []interface{}{}
//  params[0] = p1
//  params[1] = p2
//  for i, p := range ellipsisParam {
//      params[2+i]	= p
//  }
func storeParams(params *ast.FieldList) ([]ast.Stmt, error) {
	code := ""
	// Is there an ellipsis parameter?
	listlen := len(params.List)
	if listlen > 0 {
		last := params.List[len(params.List)-1]
		if _, ok := last.Type.(*ast.Ellipsis); ok {
			code += fmt.Sprintf("\tparams := make([]interface{}, %d + len(%s))\n", params.NumFields()-1, last.Names[0].Name)
		}
	}

	if code == "" {
		// No ellipsis
		code += fmt.Sprintf("\tparams := make([]interface{}, %d)\n", params.NumFields())
	}

	i := 0
	for _, f := range params.List {
		for _, n := range f.Names {
			if _, ok := f.Type.(*ast.Ellipsis); ok {
				// Ellipsis expression
				code += fmt.Sprintf(`
    for j, p := range %s {
    	params[%d+j] = p
    }
`, n.Name, i)
			} else {
				code += fmt.Sprintf("\tparams[%d] = %s\n", i, n.Name)
			}
			i++
		}
	}

	return parseCodeBlock(code)
}

// trackCall builds the ast for the call expression.
//
// The call looks like
//     r := i.TrackCall("method", params...)
//
// If there are no return values r := is omitted
func trackCall(numReturns int, methodName string) ([]ast.Stmt, error) {
	if numReturns == 0 {
		return parseCodeBlock(fmt.Sprintf("\ti.TrackCall(\"%s\", params...)", methodName))
	}
	return parseCodeBlock(fmt.Sprintf("\tr := i.TrackCall(\"%s\", params...)", methodName))
}

// declReturnValues builds the return part of the call
//
func declReturnValues(results *ast.FieldList) ([]ast.Stmt, error) {
	if results.NumFields() == 0 {
		return nil, nil
	}
	stmts := []ast.Stmt{}
	for i, f := range results.List {
		// var r_X type
		stmts = append(stmts, &ast.DeclStmt{
			Decl: &ast.GenDecl{
				Tok: token.VAR,
				Specs: []ast.Spec{
					&ast.ValueSpec{
						Names: []*ast.Ident{
							ast.NewIdent(fmt.Sprintf("r_%d", i)),
						},
						Type: f.Type,
					},
				},
			},
		})
		// if r[X] != nil {
		//     r_X = r[X].(type)
		// }
		stmts = append(stmts, &ast.IfStmt{
			Cond: &ast.BinaryExpr{
				X: &ast.IndexExpr{
					X: ast.NewIdent("r"),
					Index: &ast.BasicLit{
						Kind:  token.INT,
						Value: fmt.Sprintf("%d", i),
					},
				},
				Op: token.NEQ,
				Y:  ast.NewIdent("nil"),
			},
			Body: &ast.BlockStmt{
				List: []ast.Stmt{
					&ast.AssignStmt{
						Lhs: []ast.Expr{
							ast.NewIdent(fmt.Sprintf("r_%d", i)),
						},
						Tok: token.ASSIGN,
						Rhs: []ast.Expr{
							&ast.TypeAssertExpr{
								X: &ast.IndexExpr{
									X: ast.NewIdent("r"),
									Index: &ast.BasicLit{
										Kind:  token.INT,
										Value: fmt.Sprintf("%d", i),
									},
								},
								Type: f.Type,
							},
						},
					},
				},
			},
		})
	}

	return stmts, nil
}

// buildReturnStatement
//
// return r_0, r_1, r_2
func buildReturnStatement(count int) ([]ast.Stmt, error) {
	r := &ast.ReturnStmt{}
	for i := 0; i < count; i++ {
		r.Results = append(r.Results, ast.NewIdent(fmt.Sprintf("r_%d", i)))
	}
	return []ast.Stmt{r}, nil
}

func wrapCode(f *flags, code string) string {
	return fmt.Sprintf(`package %s

import (
	"github.com/philpearl/ut"
)

%s`, f.packageName, code)
}

func generateMock(f *flags) {
	fset := token.NewFileSet()
	p, err := parser.ParseFile(fset, f.gofile, nil, 0)
	if err != nil {
		panic(err)
	}

	v := &InterfaceVisitor{fset: fset, name: f.ifName}
	ast.Walk(v, p)

	outfile := f.outfile
	if outfile == "" {
		outfile = fmt.Sprintf("mock%s.go", strings.ToLower(f.ifName))
	}

	code := wrapCode(f, v.code)

	err = ioutil.WriteFile(outfile, []byte(code), 0666)
	if err != nil {
		fmt.Printf("Failed to open %s for writing", outfile)
		os.Exit(2)
	}
}

type flags struct {
	gofile      string
	ifName      string
	outfile     string
	packageName string
}

func (f *flags) validate() bool {
	if f.gofile == "" {
		return false
	}
	if f.ifName == "" {
		return false
	}
	if f.packageName == "" {
		return false
	}
	return true
}

func (f *flags) setup() {
	flag.StringVar(&f.gofile, "filename", "", "The file that contains the interface definition; Must be specified.")
	flag.StringVar(&f.ifName, "interface", "", "The interface that we should create a mock for; Must be specified.")
	flag.StringVar(&f.outfile, "outfile", "", "The file to create the mock in. By default will use mock<interface>.go in the current directory.")
	flag.StringVar(&f.packageName, "package", "", "Package name to use for the mock file; Must be specified.")
}

func main() {
	f := &flags{}
	f.setup()

	flag.Parse()

	if !f.validate() {
		flag.Usage()
		os.Exit(2)
	}

	generateMock(f)
}
<commit_msg>sort out imports<commit_after>package main

// TODO:::
// 1 Need some imports for parameters and returns used in the mocks
// 2 A NewMockXXXX method is handy
// 2 Some routines to allow chaining of AddCall and SetReturns

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"strings"
)

// blockVisitor walks the AST and extracts the first Block Statement it finds.
// We only use it when we've generated the code ourselves so we know there is only
// one code block to look for
type blockVisitor struct {
	stmts []ast.Stmt
}

func (v *blockVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.BlockStmt:
		v.stmts = n.List
		return nil
	}
	return v
}

type findUsedImports struct {
	names map[string]struct{}
}

func newFindUsedImports() *findUsedImports {
	return &findUsedImports{make(map[string]struct{})}
}

func (v *findUsedImports) Visit(n ast.Node) ast.Visitor {
	sel, ok := n.(*ast.SelectorExpr)
	if ok {
		id, ok := sel.X.(*ast.Ident)
		if ok {
			v.names[id.Name] = struct{}{}
		}
	}
	return v
}

// isUsed indicates whether an import is used.
//
// Import specs can either just be a path, in which case the last
// path component is the name, so it can also have a separate name
func (v *findUsedImports) isUsed(s *ast.ImportSpec) bool {
	if s.Name != nil {
		_, ok := v.names[s.Name.Name]
		return ok
	}

	path := s.Path.Value
	if path[0] == '"' {
		path = path[1:]
	}
	if path[len(path)-1] == '"' {
		path = path[:len(path)-1]
	}
	parts := strings.Split(path, "/")

	name := parts[len(parts)-1]
	_, ok := v.names[name]
	return ok
}

// InterfaceVisitor walks the AST and finds interfaces
type InterfaceVisitor struct {
	fset        *token.FileSet
	name        string
	code        string
	packageName string
	imports     []*ast.ImportSpec
}

func (i *InterfaceVisitor) Visit(n ast.Node) ast.Visitor {
	switch n := n.(type) {
	case *ast.TypeSpec:
		t, ok := n.Type.(*ast.InterfaceType)
		if ok {
			// This is an interface
			if n.Name.Name != i.name {
				return nil
			}
			i.code = i.buildMockForInterface(t)
			return nil
		}
	case *ast.ImportSpec:
		i.imports = append(i.imports, n)
	}

	return i
}

func (i *InterfaceVisitor) buildMockForInterface(t *ast.InterfaceType) string {
	var buf bytes.Buffer

	fi := newFindUsedImports()

	nodes := []ast.Decl{}

	// Mock Implementation of the interface
	m := buildMockStruct(i.name)
	ast.Walk(fi, m)
	nodes = append(nodes, m)

	// Method receiver for our mock interface
	recv := buildMethodReceiver(i.name)

	for _, m := range t.Methods.List {
		t, ok := m.Type.(*ast.FuncType)
		if ok {
			// Names for return values causes problems, so remove them.
			if t.Results != nil {
				removeFieldNames(t.Results)
			}

			// We can have multiple names for a method type if multiple
			// methods are declared with the same signature
			for _, n := range m.Names {
				fd := buildMockMethod(recv, n.Name, t)
				ast.Walk(fi, fd)
				nodes = append(nodes, fd)
			}
		}
	}

	usedImports := []ast.Spec{}
	utSpec := &ast.ImportSpec{
		Path: &ast.BasicLit{
			Kind:  token.STRING,
			Value: "\"github.com/philpearl/ut\"",
		},
	}

	for _, is := range i.imports {
		if fi.isUsed(is) {
			usedImports = append(usedImports, is)
		}
	}

	usedImports = append(usedImports, utSpec)

	fmt.Printf("%d used imports", len(usedImports))

	imp := &ast.GenDecl{
		Tok:    token.IMPORT,
		Specs:  usedImports,
		Lparen: token.Pos(1), // This is a hack to get all the imports to appear
	}

	nodes = append([]ast.Decl{imp}, nodes...)

	f := &ast.File{
		Name:  ast.NewIdent(i.packageName),
		Decls: nodes,
	}

	ast.SortImports(i.fset, f)

	printer.Fprint(&buf, i.fset, f)

	return buf.String()
}

// removeFieldNames removes names from the FieldList in place.
// This is used to remove names from return values
func removeFieldNames(fl *ast.FieldList) {
	l := []*ast.Field{}
	for _, f := range fl.List {
		if f.Names == nil {
			l = append(l, f)
		} else {
			for range f.Names {
				nf := *f
				nf.Names = nil
				l = append(l, &nf)
			}
		}
	}
	fl.List = l
}

// parseCodeBlock() parses a block of code.
//
// It works by embedding the code in a dummy go file with a function, then
// extracting the AST for the code block we're interested in
func parseCodeBlock(code string) ([]ast.Stmt, error) {
	// Embed the code in a function and add a package
	code = "package dummy\nfunc dummy() {\n" + code + "\n}\n"

	// Parse the code
	fset := token.NewFileSet()
	af, err := parser.ParseFile(fset, "dummy.go", code, 0)
	if err != nil {
		return nil, err
	}

	// Extract the statements we need
	v := &blockVisitor{}
	ast.Walk(v, af)

	return v.stmts, nil
}

func buildMockStruct(name string) *ast.GenDecl {
	return &ast.GenDecl{
		Tok: token.TYPE,
		Specs: []ast.Spec{
			&ast.TypeSpec{
				Name: ast.NewIdent(fmt.Sprintf("Mock%s", name)),
				Type: &ast.StructType{
					Fields: &ast.FieldList{
						List: []*ast.Field{
							{
								Type: &ast.SelectorExpr{
									X:   ast.NewIdent("ut"),
									Sel: ast.NewIdent("CallTracker"),
								},
							},
						},
					},
				},
			},
		},
	}
}

func buildMethodReceiver(name string) *ast.FieldList {
	return &ast.FieldList{
		List: []*ast.Field{
			{
				Names: []*ast.Ident{
					ast.NewIdent("i"),
				},
				Type: &ast.StarExpr{
					X: ast.NewIdent(fmt.Sprintf("Mock%s", name)),
				},
			},
		},
	}
}

/* buildMockMethod builds the AST for the mock method.
The function body needs to look something like:

	r := ut.TrackCall("method", param1, param2)
	return r[0].(int), r[1].(thing)

... except we need to worry about types a little more for the
return values.  So instead we do

	r := ut.TrackCall("method", param1, param2)
	var r_0 int
	var r_1 thing
	if r[0] != nil { r_0 = r[0].(int) }
	if r[1] != nil { r_1 = r[1].(thing) }
	return r_0, r_1

... and we might have an ellipsis parameter so in fact we do

	params := make([]interface{}, 2)
	params[0] = param1
	params[1] = param2
	r := ut.TrackCall("method", params...)
	var r_0 int
	var r_1 thing
	if r[0] != nil { r_0 = r[0].(int) }
	if r[1] != nil { r_1 = r[1].(thing) }
	return r_0, r_1
*/
func buildMockMethod(recv *ast.FieldList, name string, t *ast.FuncType) *ast.FuncDecl {
	stmts := []ast.Stmt{}
	p, err := storeParams(t.Params)
	if err != nil {
		fmt.Printf("Failed to set up call parameters. %v", err)
	}
	stmts = append(stmts, p...)
	p, err = trackCall(t.Results.NumFields(), name)
	if err != nil {
		fmt.Printf("failed to track call. %v", err)
	}
	stmts = append(stmts, p...)

	p, err = declReturnValues(t.Results)
	if err != nil {
		fmt.Printf("failed to declare return values. %v", err)
	}
	stmts = append(stmts, p...)

	p, err = buildReturnStatement(t.Results.NumFields())
	if err != nil {
		fmt.Printf("failed to build return statement. %v", err)
	}
	if p != nil {
		stmts = append(stmts, p...)
	}

	// This is our method declaration
	return &ast.FuncDecl{
		Type: t,
		Name: ast.NewIdent(name),
		Recv: recv,
		Body: &ast.BlockStmt{
			List: stmts,
		},
	}
}

// storeParams handles parameters
//
// Because our parameters may contain an ellipsis we always need to add all the parameters
// to an interface{} array
//
//  params := []interface{}{}
//  params[0] = p1
//  params[1] = p2
//  for i, p := range ellipsisParam {
//      params[2+i]	= p
//  }
func storeParams(params *ast.FieldList) ([]ast.Stmt, error) {
	code := ""
	// Is there an ellipsis parameter?
	listlen := len(params.List)
	if listlen > 0 {
		last := params.List[len(params.List)-1]
		if _, ok := last.Type.(*ast.Ellipsis); ok {
			code += fmt.Sprintf("\tparams := make([]interface{}, %d + len(%s))\n", params.NumFields()-1, last.Names[0].Name)
		}
	}

	if code == "" {
		// No ellipsis
		code += fmt.Sprintf("\tparams := make([]interface{}, %d)\n", params.NumFields())
	}

	i := 0
	for _, f := range params.List {
		for _, n := range f.Names {
			if _, ok := f.Type.(*ast.Ellipsis); ok {
				// Ellipsis expression
				code += fmt.Sprintf(`
    for j, p := range %s {
    	params[%d+j] = p
    }
`, n.Name, i)
			} else {
				code += fmt.Sprintf("\tparams[%d] = %s\n", i, n.Name)
			}
			i++
		}
	}

	return parseCodeBlock(code)
}

// trackCall builds the ast for the call expression.
//
// The call looks like
//     r := i.TrackCall("method", params...)
//
// If there are no return values r := is omitted
func trackCall(numReturns int, methodName string) ([]ast.Stmt, error) {
	if numReturns == 0 {
		return parseCodeBlock(fmt.Sprintf("\ti.TrackCall(\"%s\", params...)", methodName))
	}
	return parseCodeBlock(fmt.Sprintf("\tr := i.TrackCall(\"%s\", params...)", methodName))
}

// declReturnValues builds the return part of the call
//
func declReturnValues(results *ast.FieldList) ([]ast.Stmt, error) {
	if results.NumFields() == 0 {
		return nil, nil
	}
	stmts := []ast.Stmt{}
	for i, f := range results.List {
		// var r_X type
		stmts = append(stmts, &ast.DeclStmt{
			Decl: &ast.GenDecl{
				Tok: token.VAR,
				Specs: []ast.Spec{
					&ast.ValueSpec{
						Names: []*ast.Ident{
							ast.NewIdent(fmt.Sprintf("r_%d", i)),
						},
						Type: f.Type,
					},
				},
			},
		})
		// if r[X] != nil {
		//     r_X = r[X].(type)
		// }
		stmts = append(stmts, &ast.IfStmt{
			Cond: &ast.BinaryExpr{
				X: &ast.IndexExpr{
					X: ast.NewIdent("r"),
					Index: &ast.BasicLit{
						Kind:  token.INT,
						Value: fmt.Sprintf("%d", i),
					},
				},
				Op: token.NEQ,
				Y:  ast.NewIdent("nil"),
			},
			Body: &ast.BlockStmt{
				List: []ast.Stmt{
					&ast.AssignStmt{
						Lhs: []ast.Expr{
							ast.NewIdent(fmt.Sprintf("r_%d", i)),
						},
						Tok: token.ASSIGN,
						Rhs: []ast.Expr{
							&ast.TypeAssertExpr{
								X: &ast.IndexExpr{
									X: ast.NewIdent("r"),
									Index: &ast.BasicLit{
										Kind:  token.INT,
										Value: fmt.Sprintf("%d", i),
									},
								},
								Type: f.Type,
							},
						},
					},
				},
			},
		})
	}

	return stmts, nil
}

// buildReturnStatement
//
// return r_0, r_1, r_2
func buildReturnStatement(count int) ([]ast.Stmt, error) {
	r := &ast.ReturnStmt{}
	for i := 0; i < count; i++ {
		r.Results = append(r.Results, ast.NewIdent(fmt.Sprintf("r_%d", i)))
	}
	return []ast.Stmt{r}, nil
}

func generateMock(f *flags) {
	fset := token.NewFileSet()
	p, err := parser.ParseFile(fset, f.gofile, nil, 0)
	if err != nil {
		panic(err)
	}

	v := &InterfaceVisitor{fset: fset, name: f.ifName, packageName: f.packageName}
	ast.Walk(v, p)

	outfile := f.outfile
	if outfile == "" {
		outfile = fmt.Sprintf("mock%s.go", strings.ToLower(f.ifName))
	}

	err = ioutil.WriteFile(outfile, []byte(v.code), 0666)
	if err != nil {
		fmt.Printf("Failed to open %s for writing", outfile)
		os.Exit(2)
	}
}

type flags struct {
	gofile      string
	ifName      string
	outfile     string
	packageName string
}

func (f *flags) validate() bool {
	if f.gofile == "" {
		return false
	}
	if f.ifName == "" {
		return false
	}
	if f.packageName == "" {
		return false
	}
	return true
}

func (f *flags) setup() {
	flag.StringVar(&f.gofile, "filename", "", "The file that contains the interface definition; Must be specified.")
	flag.StringVar(&f.ifName, "interface", "", "The interface that we should create a mock for; Must be specified.")
	flag.StringVar(&f.outfile, "outfile", "", "The file to create the mock in. By default will use mock<interface>.go in the current directory.")
	flag.StringVar(&f.packageName, "package", "", "Package name to use for the mock file; Must be specified.")
}

func main() {
	f := &flags{}
	f.setup()

	flag.Parse()

	if !f.validate() {
		flag.Usage()
		os.Exit(2)
	}

	generateMock(f)
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Bertrand Janin <b@janin.com>
// Use of this source code is governed by the ISC license in the LICENSE file.

package main

import (
	"regexp"
	"strings"
)

var (
	// Detect a PRIVMSG (most user communications).
	rePrivMsg = regexp.MustCompile(`^:([^!]+)![^@]+@[^\s]+\sPRIVMSG\s([^\s]+)\s:(.*)`)

	// Detect if we are addressed to.
	reAddressed = regexp.MustCompile(`^(\w+)[:,.]+\s*(.*)`)
)

type PrivMsg struct {
	Nick string
	Channel string
	Body string
	IsAction bool
	IsAddressed bool
	Command string
	Args []string
}

func NewPrivMsg(line string) *PrivMsg {
	tokens := rePrivMsg.FindStringSubmatch(line)
	if tokens == nil {
		return nil
	}

	msg := &PrivMsg{
		Nick: tokens[1],
		Channel: tokens[2],
		Body: tokens[3],
	}

	if strings.HasPrefix(msg.Body, "\x01ACTION ") {
		msg.Body = msg.Body[8 : len(msg.Body)-1]
		msg.IsAction = true
	}

	// If the message is addressed (e.g. "ygor: hi"), remove the prefix
	// from the body and flag this message.
	msg.IsAddressed = false
	tokens = reAddressed.FindStringSubmatch(msg.Body)
	if tokens != nil && tokens[1] == cmd.Nickname {
		msg.IsAddressed = true
		msg.Body = tokens[2]
	}

	tokens = strings.Split(msg.Body, " ")
	if len(tokens) > 0 {
		// Check if the first token is an alias.
		alias := GetAlias(tokens[0])
		if alias != nil {
			msg.Command, msg.Args = alias.SplitValue()
		} else {
			msg.Command = tokens[0]
		}

		// Did not find a matching alias, use the provided data.
		if msg.Command == "" {
			msg.Command = tokens[0]
		}

		if len(tokens) > 1 {
			msg.Args = append(msg.Args, tokens[1:]...)
		}
	}

	return msg
}
<commit_msg>Closes #1<commit_after>// Copyright (c) 2014 Bertrand Janin <b@janin.com>
// Use of this source code is governed by the ISC license in the LICENSE file.

package main

import (
	"regexp"
	"strings"
)

var (
	// Detect a PRIVMSG (most user communications).
	rePrivMsg = regexp.MustCompile(`^:([^!]+)![^@]+@[^\s]+\sPRIVMSG\s([^\s]+)\s:(.*)`)

	// Detect if we are addressed to.
	reAddressed = regexp.MustCompile(`^(\w+)[:,. ]+\s*(.*)`)
)

type PrivMsg struct {
	Nick string
	Channel string
	Body string
	IsAction bool
	IsAddressed bool
	Command string
	Args []string
}

func NewPrivMsg(line string) *PrivMsg {
	tokens := rePrivMsg.FindStringSubmatch(line)
	if tokens == nil {
		return nil
	}

	msg := &PrivMsg{
		Nick: tokens[1],
		Channel: tokens[2],
		Body: tokens[3],
	}

	if strings.HasPrefix(msg.Body, "\x01ACTION ") {
		msg.Body = msg.Body[8 : len(msg.Body)-1]
		msg.IsAction = true
	}

	// If the message is addressed (e.g. "ygor: hi"), remove the prefix
	// from the body and flag this message.
	msg.IsAddressed = false
	tokens = reAddressed.FindStringSubmatch(msg.Body)
	if tokens != nil && tokens[1] == cmd.Nickname {
		msg.IsAddressed = true
		msg.Body = tokens[2]
	}

	tokens = strings.Split(msg.Body, " ")
	if len(tokens) > 0 {
		// Check if the first token is an alias.
		alias := GetAlias(tokens[0])
		if alias != nil {
			msg.Command, msg.Args = alias.SplitValue()
		} else {
			msg.Command = tokens[0]
		}

		// Did not find a matching alias, use the provided data.
		if msg.Command == "" {
			msg.Command = tokens[0]
		}

		if len(tokens) > 1 {
			msg.Args = append(msg.Args, tokens[1:]...)
		}
	}

	return msg
}
<|endoftext|>


<commit_before>// Package goarabic contains utility functions for working with Arabic strings.
package goarabic

// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

// SmartLength returns the length of the given string
// without considering the Arabic Vowels (Tashkeel).
func SmartLength(s *string) int {
	// len() use int as return value, so we'd better follow for compatibility
	length := 0

	for _, value := range *s {
		if tashkeel[value] {
			continue
		}
		length++
	}

	return length
}

// RemoveTashkeel returns its argument as rune-wise string without Arabic vowels (Tashkeel).
func RemoveTashkeel(s string) string {
	// var r []rune
	// the capcity of the slice wont be greater than the length of the string itself
	// hence, cap = len(s)
	r := make([]rune, 0, len(s))

	for _, value := range s {
		if tashkeel[value] {
			continue
		}
		r = append(r, value)
	}

	return string(r)
}

// RemoveTatweel returns its argument as rune-wise string without Arabic Tatweel character.
func RemoveTatweel(s string) string {
	r := make([]rune, 0, len(s))

	for _, value := range s {
		if TATWEEL.equals(value) {
			continue
		}
		r = append(r, value)
	}

	return string(r)
}
func getCharGlyph(previousChar, currentChar, nextChar rune) rune {
	glyph := currentChar
	previousIn := false // in the Arabic Alphabet or not
	nextIn := false     // in the Arabic Alphabet or not

	for _, s := range alphabet {
		if s.equals(previousChar) { // previousChar in the Arabic Alphabet ?
			previousIn = true
		}

		if s.equals(nextChar) { // nextChar in the Arabic Alphabet ?
			nextIn = true
		}
	}

	for _, s := range alphabet {

		if !s.equals(currentChar) { // currentChar in the Arabic Alphabet ?
			continue
		}

		if previousIn && nextIn { // between two Arabic Alphabet, return the medium glyph
			for s, _ := range beggining_after {
				if s.equals(previousChar) {
					return getHarf(currentChar).Beggining
				}
			}

			return getHarf(currentChar).Medium
		}

		if nextIn { // beginning (because the previous is not in the Arabic Alphabet)
			return getHarf(currentChar).Beggining
		}

		if previousIn { // final (because the next is not in the Arabic Alphabet)
			for s, _ := range beggining_after {
				if s.equals(previousChar) {
					return getHarf(currentChar).Isolated
				}
			}
			return getHarf(currentChar).Final
		}

		if !previousIn && !nextIn {
			return getHarf(currentChar).Isolated
		}

	}
	return glyph
}

// equals() return if true if the given Arabic char is alphabetically equal to
// the current Harf regardless its shape (Glyph)
func (c *Harf) equals(char rune) bool {
	switch char {
	case c.Unicode:
		return true
	case c.Beggining:
		return true
	case c.Isolated:
		return true
	case c.Medium:
		return true
	case c.Final:
		return true
	default:
		return false
	}
}

// getHarf gets the correspondent Harf for the given Arabic char
func getHarf(char rune) Harf {
	for _, s := range alphabet {
		if s.equals(char) {
			return s
		}
	}

	return Harf{Unicode: char, Isolated: char, Medium: char, Final: char}
}

// ToGlyph returns the glyph representation of the given text
func ToGlyph(text string) string {
	var (
		prev, next rune
		newText    []rune
	)

	runes := []rune(text)
	length := len(runes)

	for i, current := range runes {
		// get the previous char
		if (i - 1) < 0 {
			prev = 0
		} else {
			prev = runes[i-1]
		}

		// get the next char
		if (i + 1) <= length-1 {
			next = runes[i+1]
		} else {
			next = 0
		}

		// get the current char representation or return the same if unnecessary
		glyph := getCharGlyph(prev, current, next)

		// append the new char representation to the newText
		newText = append(newText, glyph)
	}

	return string(newText)
}

// RemoveTashkeel returns its argument as rune-wise string without Arabic vowels (Tashkeel).
/*
func RemoveTashkeelExtended(s string) string {
	r := []rune(s)

	m := map[string]bool{"\u064e": true, "\u064b": true, "\u064f": true,
		"\u064c": true, "\u0650": true, "\u064d": true,
		"\u0651": true, "\u0652": true}

	for key, value := range s {
		if m[value] {
			continue
		}
		r[key] = value
	}

	return string(r)
}
*/
<commit_msg>Explicitly set the capacity of newText.<commit_after>// Package goarabic contains utility functions for working with Arabic strings.
package goarabic

// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

// SmartLength returns the length of the given string
// without considering the Arabic Vowels (Tashkeel).
func SmartLength(s *string) int {
	// len() use int as return value, so we'd better follow for compatibility
	length := 0

	for _, value := range *s {
		if tashkeel[value] {
			continue
		}
		length++
	}

	return length
}

// RemoveTashkeel returns its argument as rune-wise string without Arabic vowels (Tashkeel).
func RemoveTashkeel(s string) string {
	// var r []rune
	// the capcity of the slice wont be greater than the length of the string itself
	// hence, cap = len(s)
	r := make([]rune, 0, len(s))

	for _, value := range s {
		if tashkeel[value] {
			continue
		}
		r = append(r, value)
	}

	return string(r)
}

// RemoveTatweel returns its argument as rune-wise string without Arabic Tatweel character.
func RemoveTatweel(s string) string {
	r := make([]rune, 0, len(s))

	for _, value := range s {
		if TATWEEL.equals(value) {
			continue
		}
		r = append(r, value)
	}

	return string(r)
}
func getCharGlyph(previousChar, currentChar, nextChar rune) rune {
	glyph := currentChar
	previousIn := false // in the Arabic Alphabet or not
	nextIn := false     // in the Arabic Alphabet or not

	for _, s := range alphabet {
		if s.equals(previousChar) { // previousChar in the Arabic Alphabet ?
			previousIn = true
		}

		if s.equals(nextChar) { // nextChar in the Arabic Alphabet ?
			nextIn = true
		}
	}

	for _, s := range alphabet {

		if !s.equals(currentChar) { // currentChar in the Arabic Alphabet ?
			continue
		}

		if previousIn && nextIn { // between two Arabic Alphabet, return the medium glyph
			for s, _ := range beggining_after {
				if s.equals(previousChar) {
					return getHarf(currentChar).Beggining
				}
			}

			return getHarf(currentChar).Medium
		}

		if nextIn { // beginning (because the previous is not in the Arabic Alphabet)
			return getHarf(currentChar).Beggining
		}

		if previousIn { // final (because the next is not in the Arabic Alphabet)
			for s, _ := range beggining_after {
				if s.equals(previousChar) {
					return getHarf(currentChar).Isolated
				}
			}
			return getHarf(currentChar).Final
		}

		if !previousIn && !nextIn {
			return getHarf(currentChar).Isolated
		}

	}
	return glyph
}

// equals() return if true if the given Arabic char is alphabetically equal to
// the current Harf regardless its shape (Glyph)
func (c *Harf) equals(char rune) bool {
	switch char {
	case c.Unicode:
		return true
	case c.Beggining:
		return true
	case c.Isolated:
		return true
	case c.Medium:
		return true
	case c.Final:
		return true
	default:
		return false
	}
}

// getHarf gets the correspondent Harf for the given Arabic char
func getHarf(char rune) Harf {
	for _, s := range alphabet {
		if s.equals(char) {
			return s
		}
	}

	return Harf{Unicode: char, Isolated: char, Medium: char, Final: char}
}

// ToGlyph returns the glyph representation of the given text
func ToGlyph(text string) string {
	var prev, next rune

	newText := make([]rune, 0, length)
	runes := []rune(text)
	length := len(runes)

	for i, current := range runes {
		// get the previous char
		if (i - 1) < 0 {
			prev = 0
		} else {
			prev = runes[i-1]
		}

		// get the next char
		if (i + 1) <= length-1 {
			next = runes[i+1]
		} else {
			next = 0
		}

		// get the current char representation or return the same if unnecessary
		glyph := getCharGlyph(prev, current, next)

		// append the new char representation to the newText
		newText = append(newText, glyph)
	}

	return string(newText)
}

// RemoveTashkeel returns its argument as rune-wise string without Arabic vowels (Tashkeel).
/*
func RemoveTashkeelExtended(s string) string {
	r := []rune(s)

	m := map[string]bool{"\u064e": true, "\u064b": true, "\u064f": true,
		"\u064c": true, "\u0650": true, "\u064d": true,
		"\u0651": true, "\u0652": true}

	for key, value := range s {
		if m[value] {
			continue
		}
		r[key] = value
	}

	return string(r)
}
*/
<|endoftext|>


<commit_before>/**
 * Reads reference data from json files, generated scala libraries
 *
 * Run using:
 * 	go run generate.go
 **/

package main

import (
	"bufio"
	"fmt"
	"github.com/flowcommerce/json-reference/common"
	"github.com/flowcommerce/tools/util"
	"os"
	"regexp"
	"strings"
	"strconv"
	"unicode"
)

const Directory = "src/main/scala/io/flow/reference/data"

type Instance struct {
	Name string
	Value string
}

func writeFile(objectName string, imports string, instances []Instance) {
	path := fmt.Sprintf("%s/%s.scala", Directory, objectName)
	fo, err := os.Create(path)
	util.ExitIfError(err, fmt.Sprintf("Error creating file %s: %s", path, err))
	defer fo.Close()

	writer := bufio.NewWriter(fo)

	writer.WriteString("package io.flow.reference.data\n\n")
	writer.WriteString(fmt.Sprintf("import io.flow.reference.v0.models.%s\n\n", imports))
	writer.WriteString(fmt.Sprintf("object %s {\n\n", objectName))

	for _, instance := range(instances) {
		writer.WriteString(fmt.Sprintf("  val %s = %s\n", scalaName(instance.Name), instance.Value))
	}
	writer.WriteString("\n")

	writer.WriteString("  val all = Seq(\n    ")
	for i, instance := range(instances) {
		if i > 0 {
			writer.WriteString(",\n    ")
		}
		writer.WriteString(scalaName(instance.Name))
	}
	writer.WriteString("\n  )\n\n}\n")

	err = writer.Flush()
	util.ExitIfError(err, fmt.Sprintf("Failed to flush file %s: %s", path, err))
	fmt.Printf("  ==> %s\n", path)
}

func main() {
	processLocales()
	processCountries()
	processCurrencies()
	processLanguages()
	processRegions()
	processTimezones()
	processPaymentMethods()
	processProvinces()
}

func processProvinces() {
	instances := []Instance{}
	for _, p := range common.Provinces() {
		instances = append(instances, Instance{
			Name: p.Id,
			Value: fmt.Sprintf("Province(id = \"%s\", iso31662 = \"%s\", name = \"%s\", country = \"%s\", provinceType = io.flow.reference.v0.models.ProvinceType(\"%s\"))", p.Id, p.Iso_3166_2, p.Name, p.Country, p.ProvinceType),
		})
	}

	writeFile("Provinces", "Province", instances)
}

func processCountries() {
	instances := []Instance{}
	for _, c := range common.Countries() {
		measurementSystem := c.MeasurementSystem

		var defaultCurrency string
		if c.DefaultCurrency == "" {
			defaultCurrency = "None"
		} else {
			defaultCurrency = fmt.Sprintf("Some(\"%s\")", c.DefaultCurrency)
		}

		instances = append(instances, Instance{
			Name: c.Iso_3166_3,
			Value: fmt.Sprintf("Country(iso31662 = \"%s\", iso31663 = \"%s\", defaultCurrency = %s, measurementSystem = \"%s\", name = \"%s\", languages = %s, timezones = %s)", c.Iso_3166_2, c.Iso_3166_3, defaultCurrency, measurementSystem, c.Name, scalaArrayQuoted(c.Languages), scalaArrayQuoted(c.Timezones)),
		})
	}

	writeFile("Countries", "Country", instances)
}

func processRegions() {
	instances := []Instance{}
	for _, r := range common.Regions() {
		measurementSystems := []string{}
		for _, system := range(r.MeasurementSystems) {
			measurementSystems = append(measurementSystems, system)
		}

		instances = append(instances, Instance{
			Name: r.Name,
			Value: fmt.Sprintf("Region(id = \"%s\", name = \"%s\", countries = %s, languages = %s, currencies = %s, measurementSystems = %s, timezones = %s)", r.Id, r.Name, scalaArrayQuoted(r.Countries), scalaArrayQuoted(r.Languages), scalaArrayQuoted(r.Currencies), scalaArrayQuoted(measurementSystems), scalaArrayQuoted(r.Timezones)),
		})
	}

	writeFile("Regions", "Region", instances)
}

func processCurrencies() {
	instances := []Instance{}
	for _, c := range common.Currencies() {
		symbols := "None"
		if c.Symbols != nil {
			narrow := "None"
			if c.Symbols.Narrow != "" {
				narrow = fmt.Sprintf("Some(\"%s\")", c.Symbols.Narrow)
			}
			symbols = fmt.Sprintf("Some(CurrencySymbols(primary = \"%s\", narrow = %s))", c.Symbols.Primary, narrow)
		}

		defaultLocale := "None"
		if c.DefaultLocale != "" {
			defaultLocale = fmt.Sprintf("Some(\"%s\")", c.DefaultLocale)
		}

		instances = append(instances, Instance{
			Name: c.Iso_4217_3,
			Value: fmt.Sprintf("Currency(iso42173 = \"%s\", name = \"%s\", numberDecimals = %v, defaultLocale = %s, symbols = %s)", c.Iso_4217_3, c.Name, c.NumberDecimals, defaultLocale, symbols),
		})
	}

	writeFile("Currencies", "{Currency, CurrencySymbols}", instances)
}

func processLanguages() {
	instances := []Instance{}
	for _, l := range common.Languages() {
		instances = append(instances, Instance{
			Name: l.Iso_639_2,
			Value: fmt.Sprintf("Language(iso6392 = \"%s\", name = \"%s\")", l.Iso_639_2, l.Name),
		})
	}

	writeFile("Languages", "Language", instances)
}

func processLocales() {
	instances := []Instance{}
	for _, l := range common.Locales() {
		instances = append(instances, Instance{
			Name: formatLocaleIdForName(l.Id),
			Value: fmt.Sprintf("Locale(id = \"%s\", name = \"%s\", country = \"%s\", language = \"%s\", numbers = LocaleNumbers(decimal = \"%s\", group = \"%s\"))", l.Id, l.Name, l.Country, l.Language, l.Numbers.Decimal, l.Numbers.Group),
		})
	}

	writeFile("Locales", "{Locale, LocaleNumbers}", instances)
}

func processTimezones() {
	instances := []Instance{}
	for _, t := range common.Timezones() {
		instances = append(instances, Instance{
			Name: t.Name,
			Value: fmt.Sprintf("Timezone(name = \"%s\", offset = %d, description = \"%s\")", t.Name, t.Offset, t.Description),
		})
	}

	writeFile("Timezones", "Timezone", instances)
}

func processPaymentMethods() {
	instances := []Instance{}
	for _, pm := range common.PaymentMethods() {
		var typ string
		if pm.Type == "card" {
			typ = "PaymentMethodType.Card"
		} else if pm.Type == "online" {
			typ = "PaymentMethodType.Online"
		} else if pm.Type == "offline" {
			typ = "PaymentMethodType.Offline"
		} else {
			fmt.Printf("ERROR: Unknown PaymentMethodType[%s]\n", pm.Type)
			os.Exit(1)
		}

		divider := "\n                                    "
		images := fmt.Sprintf("PaymentMethodImages(%s  small = %s,%s  medium = %s,%s  large = %s%s)", divider, toImage(pm.Images.Small), divider, toImage(pm.Images.Medium), divider, toImage(pm.Images.Large), divider)

		instances = append(instances, Instance{
			Name: pm.Id,
			Value: fmt.Sprintf("PaymentMethod(id = \"%s\", `type` = %s, name = \"%s\", images = %s, regions = %s)", pm.Id, typ, pm.Name, images, scalaArrayQuoted(pm.Regions)),
		})
	}

	writeFile("PaymentMethods", "{PaymentMethod, PaymentMethodImage, PaymentMethodImages, PaymentMethodType}", instances)
}

func toImage(i common.PaymentMethodImage) string {
	return fmt.Sprintf("PaymentMethodImage(url = \"%s\", width = %s, height = %s)", i.Url, strconv.Itoa(i.Width), strconv.Itoa(i.Height))
}

func scalaArrayQuoted(values []string) string {
	value := ""
	for i, v := range(values) {
		if i > 0 {
			value = value + ", ";
		}
		value = value + fmt.Sprintf("\"%s\"", v)
	}
	if value == "" {
		return "Nil"
	} else {
		return "Seq(" + value + ")";
	}
}

func scalaArrayUnquoted(values []string) string {
	value := ""
	for i, v := range(values) {
		if i > 0 {
			value = value + ", ";
		}
		value = value + v
	}
	if value == "" {
		return "Nil"
	} else {
		return "Seq(" + value + ")";
	}
}

/**
 * Turns a string name into a scala constant. We do this by:
 *  - replacing '+' with Plus
 *  - replacing '-' with Minus
 *  - replacing any other non alphanumerics into underscores, splitting
 *    on underscore, and init capping
 */
func scalaName(name string) string {
	// +, - handling for timezones
	safe := strings.Replace(name, "+", "_plus_", -1)
	safe = strings.Replace(safe, "-", "_minus_", -1)
	safe = strings.Replace(safe, "&", "and", -1)
	safe = regexp.MustCompile("[^A-Za-z0-9Åçôãéí]+").ReplaceAllString(safe, "_")

	s := ""
	for _, el := range(strings.Split(safe, "_")) {
		s = s + UpcaseInitial(strings.ToLower(el))
	}
	return s
}

func formatLocaleIdForName(id string) string {
	return strings.Replace(id, "-", "_", -1)
}

func UpcaseInitial(str string) string {
    for pos, char := range str {
        return string(unicode.ToUpper(char)) + string([]rune(str)[pos+1:])
    }
    return ""
}
<commit_msg>Fix this<commit_after>/**
 * Reads reference data from json files, generated scala libraries
 *
 * Run using:
 * 	go run generate.go
 **/

package main

import (
	"bufio"
	"fmt"
	"github.com/flowcommerce/json-reference/common"
	"github.com/flowcommerce/tools/util"
	"os"
	"regexp"
	"strings"
	"strconv"
	"unicode"
)

const Directory = "src/main/scala/io/flow/reference/data"

type Instance struct {
	Name string
	Value string
}

func writeFile(objectName string, imports string, instances []Instance) {
	path := fmt.Sprintf("%s/%s.scala", Directory, objectName)
	fo, err := os.Create(path)
	util.ExitIfError(err, fmt.Sprintf("Error creating file %s: %s", path, err))
	defer fo.Close()

	writer := bufio.NewWriter(fo)

	writer.WriteString("package io.flow.reference.data\n\n")
	writer.WriteString(fmt.Sprintf("import io.flow.reference.v0.models.%s\n\n", imports))
	writer.WriteString(fmt.Sprintf("object %s {\n\n", objectName))

	for _, instance := range(instances) {
		writer.WriteString(fmt.Sprintf("  val %s = %s\n", scalaName(instance.Name), instance.Value))
	}
	writer.WriteString("\n")

	writer.WriteString("  val all = Seq(\n    ")
	for i, instance := range(instances) {
		if i > 0 {
			writer.WriteString(",\n    ")
		}
		writer.WriteString(scalaName(instance.Name))
	}
	writer.WriteString("\n  )\n\n}\n")

	err = writer.Flush()
	util.ExitIfError(err, fmt.Sprintf("Failed to flush file %s: %s", path, err))
	fmt.Printf("  ==> %s\n", path)
}

func main() {
	processLocales()
	processCountries()
	processCurrencies()
	processLanguages()
	processRegions()
	processTimezones()
	processPaymentMethods()
	processProvinces()
}

func processProvinces() {
	instances := []Instance{}
	for _, p := range common.Provinces() {
		instances = append(instances, Instance{
			Name: strings.Replace(p.Id, "-", "_", -1),
			Value: fmt.Sprintf("Province(id = \"%s\", iso31662 = \"%s\", name = \"%s\", country = \"%s\", provinceType = io.flow.reference.v0.models.ProvinceType(\"%s\"))", p.Id, p.Iso_3166_2, p.Name, p.Country, p.ProvinceType),
		})
	}

	writeFile("Provinces", "Province", instances)
}

func processCountries() {
	instances := []Instance{}
	for _, c := range common.Countries() {
		measurementSystem := c.MeasurementSystem

		var defaultCurrency string
		if c.DefaultCurrency == "" {
			defaultCurrency = "None"
		} else {
			defaultCurrency = fmt.Sprintf("Some(\"%s\")", c.DefaultCurrency)
		}

		instances = append(instances, Instance{
			Name: c.Iso_3166_3,
			Value: fmt.Sprintf("Country(iso31662 = \"%s\", iso31663 = \"%s\", defaultCurrency = %s, measurementSystem = \"%s\", name = \"%s\", languages = %s, timezones = %s)", c.Iso_3166_2, c.Iso_3166_3, defaultCurrency, measurementSystem, c.Name, scalaArrayQuoted(c.Languages), scalaArrayQuoted(c.Timezones)),
		})
	}

	writeFile("Countries", "Country", instances)
}

func processRegions() {
	instances := []Instance{}
	for _, r := range common.Regions() {
		measurementSystems := []string{}
		for _, system := range(r.MeasurementSystems) {
			measurementSystems = append(measurementSystems, system)
		}

		instances = append(instances, Instance{
			Name: r.Name,
			Value: fmt.Sprintf("Region(id = \"%s\", name = \"%s\", countries = %s, languages = %s, currencies = %s, measurementSystems = %s, timezones = %s)", r.Id, r.Name, scalaArrayQuoted(r.Countries), scalaArrayQuoted(r.Languages), scalaArrayQuoted(r.Currencies), scalaArrayQuoted(measurementSystems), scalaArrayQuoted(r.Timezones)),
		})
	}

	writeFile("Regions", "Region", instances)
}

func processCurrencies() {
	instances := []Instance{}
	for _, c := range common.Currencies() {
		symbols := "None"
		if c.Symbols != nil {
			narrow := "None"
			if c.Symbols.Narrow != "" {
				narrow = fmt.Sprintf("Some(\"%s\")", c.Symbols.Narrow)
			}
			symbols = fmt.Sprintf("Some(CurrencySymbols(primary = \"%s\", narrow = %s))", c.Symbols.Primary, narrow)
		}

		defaultLocale := "None"
		if c.DefaultLocale != "" {
			defaultLocale = fmt.Sprintf("Some(\"%s\")", c.DefaultLocale)
		}

		instances = append(instances, Instance{
			Name: c.Iso_4217_3,
			Value: fmt.Sprintf("Currency(iso42173 = \"%s\", name = \"%s\", numberDecimals = %v, defaultLocale = %s, symbols = %s)", c.Iso_4217_3, c.Name, c.NumberDecimals, defaultLocale, symbols),
		})
	}

	writeFile("Currencies", "{Currency, CurrencySymbols}", instances)
}

func processLanguages() {
	instances := []Instance{}
	for _, l := range common.Languages() {
		instances = append(instances, Instance{
			Name: l.Iso_639_2,
			Value: fmt.Sprintf("Language(iso6392 = \"%s\", name = \"%s\")", l.Iso_639_2, l.Name),
		})
	}

	writeFile("Languages", "Language", instances)
}

func processLocales() {
	instances := []Instance{}
	for _, l := range common.Locales() {
		instances = append(instances, Instance{
			Name: formatLocaleIdForName(l.Id),
			Value: fmt.Sprintf("Locale(id = \"%s\", name = \"%s\", country = \"%s\", language = \"%s\", numbers = LocaleNumbers(decimal = \"%s\", group = \"%s\"))", l.Id, l.Name, l.Country, l.Language, l.Numbers.Decimal, l.Numbers.Group),
		})
	}

	writeFile("Locales", "{Locale, LocaleNumbers}", instances)
}

func processTimezones() {
	instances := []Instance{}
	for _, t := range common.Timezones() {
		instances = append(instances, Instance{
			Name: t.Name,
			Value: fmt.Sprintf("Timezone(name = \"%s\", offset = %d, description = \"%s\")", t.Name, t.Offset, t.Description),
		})
	}

	writeFile("Timezones", "Timezone", instances)
}

func processPaymentMethods() {
	instances := []Instance{}
	for _, pm := range common.PaymentMethods() {
		var typ string
		if pm.Type == "card" {
			typ = "PaymentMethodType.Card"
		} else if pm.Type == "online" {
			typ = "PaymentMethodType.Online"
		} else if pm.Type == "offline" {
			typ = "PaymentMethodType.Offline"
		} else {
			fmt.Printf("ERROR: Unknown PaymentMethodType[%s]\n", pm.Type)
			os.Exit(1)
		}

		divider := "\n                                    "
		images := fmt.Sprintf("PaymentMethodImages(%s  small = %s,%s  medium = %s,%s  large = %s%s)", divider, toImage(pm.Images.Small), divider, toImage(pm.Images.Medium), divider, toImage(pm.Images.Large), divider)

		instances = append(instances, Instance{
			Name: pm.Id,
			Value: fmt.Sprintf("PaymentMethod(id = \"%s\", `type` = %s, name = \"%s\", images = %s, regions = %s)", pm.Id, typ, pm.Name, images, scalaArrayQuoted(pm.Regions)),
		})
	}

	writeFile("PaymentMethods", "{PaymentMethod, PaymentMethodImage, PaymentMethodImages, PaymentMethodType}", instances)
}

func toImage(i common.PaymentMethodImage) string {
	return fmt.Sprintf("PaymentMethodImage(url = \"%s\", width = %s, height = %s)", i.Url, strconv.Itoa(i.Width), strconv.Itoa(i.Height))
}

func scalaArrayQuoted(values []string) string {
	value := ""
	for i, v := range(values) {
		if i > 0 {
			value = value + ", ";
		}
		value = value + fmt.Sprintf("\"%s\"", v)
	}
	if value == "" {
		return "Nil"
	} else {
		return "Seq(" + value + ")";
	}
}

func scalaArrayUnquoted(values []string) string {
	value := ""
	for i, v := range(values) {
		if i > 0 {
			value = value + ", ";
		}
		value = value + v
	}
	if value == "" {
		return "Nil"
	} else {
		return "Seq(" + value + ")";
	}
}

/**
 * Turns a string name into a scala constant. We do this by:
 *  - replacing '+' with Plus
 *  - replacing '-' with Minus
 *  - replacing any other non alphanumerics into underscores, splitting
 *    on underscore, and init capping
 */
func scalaName(name string) string {
	// +, - handling for timezones
	safe := strings.Replace(name, "+", "_plus_", -1)
	safe = strings.Replace(safe, "-", "_minus_", -1)
	safe = strings.Replace(safe, "&", "and", -1)
	safe = regexp.MustCompile("[^A-Za-z0-9Åçôãéí]+").ReplaceAllString(safe, "_")

	s := ""
	for _, el := range(strings.Split(safe, "_")) {
		s = s + UpcaseInitial(strings.ToLower(el))
	}
	return s
}

func formatLocaleIdForName(id string) string {
	return strings.Replace(id, "-", "_", -1)
}

func UpcaseInitial(str string) string {
    for pos, char := range str {
        return string(unicode.ToUpper(char)) + string([]rune(str)[pos+1:])
    }
    return ""
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

var cmdField = &Command{
	Run:   runField,
	Usage: "field",
	Short: "Manage sobject fields",
	Long: `
Manage sobject fields

Usage:

  force field list <object>

  force field create <object> <field>:<type> [<option>:<value>]

  force field delete <object> <field>

Examples:

  force field list Todo__c

  force field create Todo__c Due:DateTime required:true

  force field delete Todo__c Due
`,
}

func runField(cmd *Command, args []string) {
	if len(args) == 0 {
		cmd.printUsage()
	} else {
		switch args[0] {
		case "list":
			runFieldList(args[1:])
		case "create", "add":
			runFieldCreate(args[1:])
		case "delete", "remove":
			runFieldDelete(args[1:])
		case "type":
			if len(args) == 1 {
				DisplayFieldTypes();
			} else if len(args) == 2 {
				DisplayFieldDetails(args[1])
			}
		default:
			ErrorAndExit("no such command: %s", args[0])
		}
	}
}

func runFieldList(args []string) {
	if len(args) != 1 {
		ErrorAndExit("must specify object")
	}
	force, _ := ActiveForce()
	sobject, err := force.GetSobject(args[0])
	if err != nil {
		ErrorAndExit(err.Error())
	}
	DisplayForceSobject(sobject)
}

func runFieldCreate(args []string) {
	if len(args) < 2 {
		ErrorAndExit("must specify object and at least one field")
	}

	force, _ := ActiveForce()

	parts := strings.Split(args[1], ":")
	if len(parts) != 2 {
		ErrorAndExit("must specify name:type for fields")
	}

	var optionMap = make(map[string]string)
	if len(args) > 2 {
		for _, value := range args[2:] {
			options := strings.Split(value, ":")
			if len(options) != 2 {
				ErrorAndExit(fmt.Sprintf("Missing value for field attribute %s", value))
			}
			optionMap[options[0]] = options[1]
		}
	}

	// Validate the options for this field type
	newOptions, err := force.Metadata.ValidateFieldOptions(parts[1], optionMap)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := force.Metadata.CreateCustomField(args[0], parts[0], parts[1], newOptions); err != nil {
		fmt.Println("Got an error")
		ErrorAndExit(err.Error())
	}
	fmt.Println("Custom field created")
}

func runFieldDelete(args []string) {
	if len(args) < 2 {
		ErrorAndExit("must specify object and at least one field")
	}
	force, _ := ActiveForce()
	if err := force.Metadata.DeleteCustomField(args[0], args[1]); err != nil {
		ErrorAndExit(err.Error())
	}
	fmt.Println("Custom field deleted")
}
<commit_msg>added support for all other field types except picklist and added more interactive help<commit_after>package main

import (
	"fmt"
	"strings"
)

var cmdField = &Command{
	Run:   runField,
	Usage: "field",
	Short: "Manage sobject fields",
	Long: `
Manage sobject fields

Usage:

  force field list <object>

  force field create <object> <field>:<type> [<option>:<value>]

  force field delete <object> <field>

  force field type

  force field type <fieldtype>

Examples:

  force field list Todo__c

  force field create Todo__c Due:DateTime required:true

  force field delete Todo__c Due

  force field type     #displays all the supported field types

  force field type email   #displays the required and optional attributes

`,
}

func runField(cmd *Command, args []string) {
	if len(args) == 0 {
		cmd.printUsage()
	} else {
		switch args[0] {
		case "list":
			runFieldList(args[1:])
		case "create", "add":
			runFieldCreate(args[1:])
		case "delete", "remove":
			runFieldDelete(args[1:])
		case "type":
			if len(args) == 1 {
				DisplayFieldTypes();
			} else if len(args) == 2 {
				DisplayFieldDetails(args[1])
			}
		default:
			ErrorAndExit("no such command: %s", args[0])
		}
	}
}

func runFieldList(args []string) {
	if len(args) != 1 {
		ErrorAndExit("must specify object")
	}
	force, _ := ActiveForce()
	sobject, err := force.GetSobject(args[0])
	if err != nil {
		ErrorAndExit(err.Error())
	}
	DisplayForceSobject(sobject)
}

func runFieldCreate(args []string) {
	if len(args) < 2 {
		ErrorAndExit("must specify object and at least one field")
	}

	force, _ := ActiveForce()

	parts := strings.Split(args[1], ":")
	if len(parts) != 2 {
		ErrorAndExit("must specify name:type for fields")
	}

	var optionMap = make(map[string]string)
	if len(args) > 2 {
		for _, value := range args[2:] {
			options := strings.Split(value, ":")
			if len(options) != 2 {
				ErrorAndExit(fmt.Sprintf("Missing value for field attribute %s", value))
			}
			optionMap[options[0]] = options[1]
		}
	}

	// Validate the options for this field type
	newOptions, err := force.Metadata.ValidateFieldOptions(parts[1], optionMap)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := force.Metadata.CreateCustomField(args[0], parts[0], parts[1], newOptions); err != nil {
		fmt.Println("Got an error")
		ErrorAndExit(err.Error())
	}
	fmt.Println("Custom field created")
}

func runFieldDelete(args []string) {
	if len(args) < 2 {
		ErrorAndExit("must specify object and at least one field")
	}
	force, _ := ActiveForce()
	if err := force.Metadata.DeleteCustomField(args[0], args[1]); err != nil {
		ErrorAndExit(err.Error())
	}
	fmt.Println("Custom field deleted")
}
<|endoftext|>


<commit_before>package iso8583

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

const (
	ASCII = iota
	BCD
)

const (
	ERR_INVALID_ENCODER     string = "invalid encoder"
	ERR_INVALID_LENGTH_HEAD string = "invalid length head"
	ERR_MISSING_LENGTH      string = "missing length"
	ERR_VALUE_TOO_LONG      string = "length of value is longer than definition"
	ERR_BAD_RAW             string = "bad raw data"
	ERR_PARSE_LENGTH_FAILED string = "parse length head failed"
)

type Iso8583Type interface {
	// Byte representation of current field.
	Bytes(encoder, lenEncoder, length int) ([]byte, error)

	// Load unmarshal byte value into Iso8583Type according to the
	// specific arguments. It returns the number of bytes actually read.
	Load(raw []byte, encoder, lenEncoder, length int) (int, error)
}

// A Numeric contains numeric value only in fix length. It holds numeric
// value as a string. Supportted encoder are ascii and bcd. Length is
// required for marshalling and unmarshalling.
type Numeric struct {
	Value string
}

func NewNumeric(val string) *Numeric {
	return &Numeric{val}
}

func (n *Numeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	val := []byte(n.Value)
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	if len(val) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if len(val) < length {
		val = append([]byte(strings.Repeat("0", length-len(val))), val...)
	}
	switch encoder {
	case BCD:
		return lbcd(val), nil
	case ASCII:
		return val, nil
	default:
		panic(ERR_INVALID_ENCODER)
	}
}

func (n *Numeric) Load(raw []byte, encoder, lenEncoder, length int) (int, error) {
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	switch encoder {
	case BCD:
		l := (length + 1) / 2
		if len(raw) < l {
			return 0, errors.New(ERR_BAD_RAW)
		}
		n.Value = string(bcdl2Ascii(raw[:l], length))
		return l, nil
	case ASCII:
		if len(raw) < length {
			return 0, errors.New(ERR_BAD_RAW)
		}
		n.Value = string(raw[:length])
		return length, nil
	default:
		panic(ERR_INVALID_ENCODER)
	}
}

// An Alphanumeric contains alphanumeric value in fix length. The only
// supportted encoder is ascii. Length is required for marshalling and
// unmarshalling.
type Alphanumeric struct {
	Value string
}

func NewAlphanumeric(val string) *Alphanumeric {
	return &Alphanumeric{Value: val}
}

func (a *Alphanumeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	val := []byte(a.Value)
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	if len(val) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if len(val) < length {
		val = append([]byte(strings.Repeat(" ", length-len(val))), val...)
	}
	return val, nil
}

func (a *Alphanumeric) Load(raw []byte, encoder, lenEncoder, length int) (int, error) {
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	a.Value = string(raw[:length])
	return length, nil
}

type Llvar struct {
	Value string
}

func NewLlvar(val string) *Llvar {
	return &Llvar{val}
}

func (l *Llvar) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	val := []byte(l.Value)
	if length != -1 && len(val) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%02d", len(val))
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 1 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return append(lenVal, val...), nil
}

func (l *Llvar) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 2
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	case BCD:
		read = 1
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[0]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	body := raw[read : read+contentLen]
	read += contentLen
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}
	l.Value = string(body)

	return read, nil
}

type Llnumeric struct {
	Value string
}

func NewLlnumeric(val string) *Llnumeric {
	return &Llnumeric{val}
}

func (l *Llnumeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	raw := []byte(l.Value)
	if length != -1 && len(raw) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}

	val := raw
	switch encoder {
	case ASCII:
	case BCD:
		val = lbcd(raw)
	default:
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%02d", len(raw)) // length of digital characters
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 1 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return append(lenVal, val...), nil
}

func (l *Llnumeric) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 2
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	case BCD:
		read = 1
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[0]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	switch encoder {
	case ASCII:
		l.Value = string(raw[read : read+contentLen])
		read += contentLen
	case BCD:
		bcdLen := (contentLen + 1) / 2
		l.Value = string(bcdl2Ascii(raw[read:read+bcdLen], contentLen))
		read += bcdLen
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return read, nil
}

type Lllvar struct {
	Value string
}

func NewLllvar(val string) *Lllvar {
	return &Lllvar{val}
}

func (l *Lllvar) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	val := []byte(l.Value)
	if length != -1 && len(val) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}

	switch encoder {
	case ASCII:
	case BCD:
		val = lbcd(val)
	default:
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%03d", len(val))
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 3 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	}
	return append(lenVal, val...), nil
}

func (l *Lllvar) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 3
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:3]))
		}
	case BCD:
		read = 2
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	body := raw[read : read+contentLen]
	read += contentLen
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}
	l.Value = string(body)

	return read, nil
}

type Lllnumeric struct {
	Value string
}

func NewLllnumeric(val string) *Lllnumeric {
	return &Lllnumeric{val}
}

func (l *Lllnumeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	raw := []byte(l.Value)
	if length != -1 && len(raw) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}

	val := raw
	switch encoder {
	case ASCII:
	case BCD:
		val = lbcd(raw)
	default:
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%03d", len(raw)) // length of digital characters
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 3 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return append(lenVal, val...), nil
}

func (l *Lllnumeric) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 3
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:3]))
		}
	case BCD:
		read = 2
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	switch encoder {
	case ASCII:
		l.Value = string(raw[read : read+contentLen])
		read += contentLen
	case BCD:
		bcdLen := (contentLen + 1) / 2
		l.Value = string(bcdl2Ascii(raw[read:read+bcdLen], contentLen))
		read += bcdLen
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return read, nil
}
<commit_msg>support bin field<commit_after>package iso8583

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

const (
	ASCII = iota
	BCD
)

const (
	ERR_INVALID_ENCODER     string = "invalid encoder"
	ERR_INVALID_LENGTH_HEAD string = "invalid length head"
	ERR_MISSING_LENGTH      string = "missing length"
	ERR_VALUE_TOO_LONG      string = "length of value is longer than definition"
	ERR_BAD_RAW             string = "bad raw data"
	ERR_PARSE_LENGTH_FAILED string = "parse length head failed"
)

type Iso8583Type interface {
	// Byte representation of current field.
	Bytes(encoder, lenEncoder, length int) ([]byte, error)

	// Load unmarshal byte value into Iso8583Type according to the
	// specific arguments. It returns the number of bytes actually read.
	Load(raw []byte, encoder, lenEncoder, length int) (int, error)
}

// A Numeric contains numeric value only in fix length. It holds numeric
// value as a string. Supportted encoder are ascii and bcd. Length is
// required for marshalling and unmarshalling.
type Numeric struct {
	Value string
}

func NewNumeric(val string) *Numeric {
	return &Numeric{val}
}

func (n *Numeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	val := []byte(n.Value)
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	if len(val) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if len(val) < length {
		val = append([]byte(strings.Repeat("0", length-len(val))), val...)
	}
	switch encoder {
	case BCD:
		return lbcd(val), nil
	case ASCII:
		return val, nil
	default:
		panic(ERR_INVALID_ENCODER)
	}
}

func (n *Numeric) Load(raw []byte, encoder, lenEncoder, length int) (int, error) {
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	switch encoder {
	case BCD:
		l := (length + 1) / 2
		if len(raw) < l {
			return 0, errors.New(ERR_BAD_RAW)
		}
		n.Value = string(bcdl2Ascii(raw[:l], length))
		return l, nil
	case ASCII:
		if len(raw) < length {
			return 0, errors.New(ERR_BAD_RAW)
		}
		n.Value = string(raw[:length])
		return length, nil
	default:
		panic(ERR_INVALID_ENCODER)
	}
}

// An Alphanumeric contains alphanumeric value in fix length. The only
// supportted encoder is ascii. Length is required for marshalling and
// unmarshalling.
type Alphanumeric struct {
	Value string
}

func NewAlphanumeric(val string) *Alphanumeric {
	return &Alphanumeric{Value: val}
}

func (a *Alphanumeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	val := []byte(a.Value)
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	if len(val) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if len(val) < length {
		val = append([]byte(strings.Repeat(" ", length-len(val))), val...)
	}
	return val, nil
}

func (a *Alphanumeric) Load(raw []byte, encoder, lenEncoder, length int) (int, error) {
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	a.Value = string(raw[:length])
	return length, nil
}

type Binary struct {
	Value []byte
}

func NewBinary(d []byte) *Binary {
	return &Binary{d}
}

func (b *Binary) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	if len(b.Value) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if len(b.Value) < length {
		return append(b.Value, make([]byte, length-len(b.Value))...), nil
	}
	return b.Value, nil
}

func (b *Binary) Load(raw []byte, encoder, lenEncoder, length int) (int, error) {
	if length == -1 {
		panic(ERR_MISSING_LENGTH)
	}
	b.Value = raw[:length]
	return length, nil
}

type Llvar struct {
	Value []byte
}

func NewLlvar(val []byte) *Llvar {
	return &Llvar{val}
}

func (l *Llvar) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	if length != -1 && len(l.Value) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%02d", len(l.Value))
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 1 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return append(lenVal, l.Value...), nil
}

func (l *Llvar) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 2
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	case BCD:
		read = 1
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[0]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	l.Value = raw[read : read+contentLen]
	read += contentLen
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}

	return read, nil
}

type Llnumeric struct {
	Value string
}

func NewLlnumeric(val string) *Llnumeric {
	return &Llnumeric{val}
}

func (l *Llnumeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	raw := []byte(l.Value)
	if length != -1 && len(raw) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}

	val := raw
	switch encoder {
	case ASCII:
	case BCD:
		val = lbcd(raw)
	default:
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%02d", len(raw)) // length of digital characters
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 1 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return append(lenVal, val...), nil
}

func (l *Llnumeric) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 2
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	case BCD:
		read = 1
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[0]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	switch encoder {
	case ASCII:
		l.Value = string(raw[read : read+contentLen])
		read += contentLen
	case BCD:
		bcdLen := (contentLen + 1) / 2
		l.Value = string(bcdl2Ascii(raw[read:read+bcdLen], contentLen))
		read += bcdLen
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return read, nil
}

type Lllvar struct {
	Value []byte
}

func NewLllvar(val []byte) *Lllvar {
	return &Lllvar{val}
}

func (l *Lllvar) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	if length != -1 && len(l.Value) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%03d", len(l.Value))
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 3 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	}
	return append(lenVal, l.Value...), nil
}

func (l *Lllvar) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 3
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:3]))
		}
	case BCD:
		read = 2
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 3)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	l.Value = raw[read : read+contentLen]
	read += contentLen
	if encoder != ASCII {
		panic(ERR_INVALID_ENCODER)
	}

	return read, nil
}

type Lllnumeric struct {
	Value string
}

func NewLllnumeric(val string) *Lllnumeric {
	return &Lllnumeric{val}
}

func (l *Lllnumeric) Bytes(encoder, lenEncoder, length int) ([]byte, error) {
	raw := []byte(l.Value)
	if length != -1 && len(raw) > length {
		return nil, errors.New(ERR_VALUE_TOO_LONG)
	}

	val := raw
	switch encoder {
	case ASCII:
	case BCD:
		val = lbcd(raw)
	default:
		panic(ERR_INVALID_ENCODER)
	}

	lenStr := fmt.Sprintf("%03d", len(raw)) // length of digital characters
	contentLen := []byte(lenStr)
	var lenVal []byte
	switch lenEncoder {
	case ASCII:
		lenVal = contentLen
		if len(lenVal) > 3 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
	case BCD:
		if len(lenVal) > 2 {
			panic(ERR_INVALID_LENGTH_HEAD)
		}
		lenVal = rbcd(contentLen)
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return append(lenVal, val...), nil
}

func (l *Lllnumeric) Load(raw []byte, encoder, lenEncoder, length int) (read int, err error) {
	// parse length head:
	var contentLen int
	switch lenEncoder {
	case ASCII:
		read = 3
		contentLen, err = strconv.Atoi(string(raw[:read]))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:3]))
		}
	case BCD:
		read = 2
		contentLen, err = strconv.Atoi(string(bcdr2Ascii(raw[:read], 2)))
		if err != nil {
			return 0, errors.New(ERR_PARSE_LENGTH_FAILED + ": " + string(raw[:2]))
		}
	default:
		panic(ERR_INVALID_ENCODER)
	}

	// parse body:
	switch encoder {
	case ASCII:
		l.Value = string(raw[read : read+contentLen])
		read += contentLen
	case BCD:
		bcdLen := (contentLen + 1) / 2
		l.Value = string(bcdl2Ascii(raw[read:read+bcdLen], contentLen))
		read += bcdLen
	default:
		panic(ERR_INVALID_ENCODER)
	}
	return read, nil
}
<|endoftext|>