package main

import (
	"log"
	"sync"
	"time"

	"srs.epita.fr/fic-server/settings"
)

// distList maintain a nextSettingsFile list up-to-date.
type distList struct {
	List  []*settings.NextSettingsFile
	Lock  sync.RWMutex
	Timer *time.Timer
}

// NewDistList creates a distList from the given src directory
func NewDistList(src string) (*distList, error) {
	list, err := settings.ListNextSettingsFiles()
	if err != nil {
		return nil, err
	}
	return &distList{List: list, Timer: time.NewTimer(time.Minute)}, nil
}

func (l *distList) TimerNextEvent() *time.Timer {
	l.Lock.RLock()
	defer l.Lock.RUnlock()

	var min *time.Time

	for _, f := range l.List {
		if min == nil || f.Date.Before(*min) {
			min = &f.Date
		}
	}

	if min == nil {
		return nil
	}

	if min == nil {
		return nil
	}

	return time.NewTimer(time.Until(*min))
}

func (l *distList) AddEvent(nsf *settings.NextSettingsFile) {
	l.Lock.Lock()

	istop := len(l.List)
	for i, n := range l.List {
		if n.Id == nsf.Id {
			return
		} else if n.Date.After(nsf.Date) {
			istop = i
			break
		}
	}

	l.List = append(l.List, nsf)
	copy(l.List[istop+1:], l.List[istop:])
	l.List[istop] = nsf

	l.Lock.Unlock()

	if istop == 0 {
		l.ResetTimer()
	}
}

func (l *distList) DelEvent(id int64) {
	l.Lock.Lock()

	istop := len(l.List)
	for i, n := range l.List {
		if n.Id == id {
			istop = i
			break
		}
	}

	if istop == len(l.List)-1 {
		l.List = l.List[:istop]
	} else if istop != len(l.List) {
		l.List = append(l.List[:istop], l.List[istop+1:]...)
	}

	l.Lock.Unlock()

	if istop == 0 {
		l.ResetTimer()
	}
}

func (l *distList) ResetTimer() {
	l.Lock.RLock()
	defer l.Lock.RUnlock()

	if len(l.List) == 0 {
		l.Timer.Reset(time.Minute)
	} else {
		l.Timer.Reset(time.Until(l.List[0].Date))
	}
}

func (l *distList) Pop() *settings.NextSettingsFile {
	l.Lock.Lock()
	defer l.Lock.Unlock()

	if len(l.List) == 0 {
		return nil
	}

	if time.Now().Before(l.List[0].Date) {
		return nil
	}

	ret := l.List[0]
	l.List = l.List[1:]
	return ret
}

func (l *distList) Print() {
	l.Lock.RLock()
	defer l.Lock.RUnlock()

	log.Println("Seeing distlist")
	for n, i := range l.List {
		log.Printf("#%d: %v", n, *i)
	}
}
