/*
 * interfaces.go
 *-------------------------------------------------------
 * Illustrating use of interfaces
 * Jim Fawcett, CSE775 - Distributed Objects, Spring 2016
 *-------------------------------------------------------
 *
 * This package simulates generics by using an anything
 * interface, e.g., accepts any type
 */
 package main
 
 import (
   "fmt"
   "fawcett/utils"
 )
 
 type Element struct { 
   next *Element
   prev *Element
   Value interface {}  // using anything interface to simulate generics
 }                     // would have better interface if this was pointer
 
 type Queue struct {
   first *Element
   last *Element
 }
 
 func (q *Queue) Init() {  // methods that modify receiver must 
   q.first = nil           // do that through a pointer 
   q.last = nil
 } 
 
 func (q *Queue) Push(e Element) {
   e.prev = nil
   e.next = q.first
   q.first = &e
   if(e.next != nil) {
     e.next.prev = &e
   }
   if(q.last == nil) {
      q.last = q.first
   }
 }
 
 func (q *Queue) Pop() Element {
   if q.last == nil {  // empty queue
     return *new(Element)
   }
   temp := q.last
   q.last.prev.next = nil
   return *temp
 }
 
 func (q Queue) Size() int {
   size := 0
   temp := q.first
   for {
     if(temp == nil) {
	   break
	 }
	 size++
	 temp = temp.next
   }
   return size
 }

 func (q Queue) Show() {
   fmt.Printf("\n  size of queue = %v\n    ", q.Size())
   temp := q.first
   for {
     if(temp == nil) {
	   break
	 }
	 fmt.Printf("%v ", temp.Value)
	 temp = temp.next
   }
 }
 func main() {
   utils.TitleM("Demonstrating interfaces")
   fmt.Println()
   utils.Title("Using Queue of ints")
   var q Queue
   q.Init()
   e := new(Element)
   e.Value = 1
   q.Push(*e)
   e = new(Element)
   e.Value = 2
   q.Push(*e)
   e = new(Element)
   e.Value = 3
   q.Push(*e)
   q.Show()
   *e = q.Pop()
   q.Show()
   fmt.Printf("\n  popped value: %v\n", e.Value)
   fmt.Println()
   
   utils.Title("Using Queue of strings")
   var q2 Queue
   q2.Init()
   e2 := new(Element)
   e2.Value = "one"
   q2.Push(*e2)
   e2 = new(Element)
   e2.Value = "two"
   q2.Push(*e2)
   e2 = new(Element)
   e2.Value = "three"
   q2.Push(*e2)
   q2.Show()
   *e2 = q2.Pop()
   q2.Show()
   fmt.Printf("\n  popped value: %v\n", e2.Value)
 }