// Copyright 2010 The postscript-go Authors. All rights reserved.
// created: 13/12/2010 by Laurent Le Goff

//Operand Stack Manipulation Operators
package postscript

//any pop – -> Discard top element
func pop(interpreter *Interpreter) {
	interpreter.Pop()
}
//any1  any2 exch any2  any1 -> Exchange top two elements
func exch(interpreter *Interpreter) {
	value1 := interpreter.Pop()
	value2 := interpreter.Pop()
	interpreter.Push(value1)
	interpreter.Push(value2)
}
//any dup any  any -> Duplicate top element
func dup(interpreter *Interpreter) {
	interpreter.Push(interpreter.Peek())
}

//any1  …  anyn  n copy any1  …  anyn  any1  …  anyn -> Duplicate top n elements
func copystack(interpreter *Interpreter) {
	n := interpreter.PopInt()
	values := interpreter.GetValues(n)
	for _, value := range values {
		interpreter.Push(value)
	}
}
//anyn  …  any0  n index anyn …  any0  anyn -> Duplicate arbitrary element
func index(interpreter *Interpreter) {
	f := interpreter.PopInt()
	interpreter.Push(interpreter.Get(int(f)))
}
//anyn−1  …  any0  n  j roll any(j−1) mod n  …  any0  anyn−1  …  anyj mod n -> Roll n elements up j times
func roll(interpreter *Interpreter) {
	j := interpreter.PopInt()
	n := interpreter.PopInt()
	values := interpreter.PopValues(n)
	j %= n
	for i := 0; i < n; i++ {
		interpreter.Push(values[(n+i-j)%n])
	}
}
//any1  …  anyn clear -> Discard all elements
func clear(interpreter *Interpreter) {
	interpreter.ClearOperands()
}
//any1  …  anyn count any1  …  anyn  n -> Count elements on stack
func count(interpreter *Interpreter) {
	interpreter.Push(interpreter.OperandSize())
}
//Mark
type Mark struct{}
//– mark mark -> Push mark on stack
func mark(interpreter *Interpreter) {
	interpreter.Push(Mark{})
}
//mark  obj 1  …  obj n cleartomark – -> Discard elements down through mark
func cleartomark(interpreter *Interpreter) {
	value := interpreter.Pop()
	for _, ok := value.(Mark); !ok; {
		value = interpreter.Pop()
	}
}
//mark  obj 1  …  obj n counttomark mark  obj 1  …  obj n  n -> Count elements down to mark
func counttomark(interpreter *Interpreter) {
	i := 0
	value := interpreter.Get(i)
	for _, ok := value.(Mark); !ok; i++ {
		value = interpreter.Get(i)
	}
	interpreter.Push(float64(i))
}

func initStackOperator(interpreter *Interpreter) {
	interpreter.SystemDefine("pop", NewOperator(pop))
	interpreter.SystemDefine("exch", NewOperator(exch))
	interpreter.SystemDefine("dup", NewOperator(dup))
	interpreter.SystemDefine("index", NewOperator(index))
	interpreter.SystemDefine("roll", NewOperator(roll))
	interpreter.SystemDefine("clear", NewOperator(clear))
	interpreter.SystemDefine("count", NewOperator(count))
	interpreter.SystemDefine("mark", NewOperator(mark))
	interpreter.SystemDefine("cleartomark", NewOperator(mark))
	interpreter.SystemDefine("counttomark", NewOperator(mark))
}
