func (f *JsonDB) CreateOrUpdateIPs(projectName string, ip []models.IP) error {
	return errors.New("Not implemented yet")
}
CreateOrUpdateIPs is not implemented yet.
It should be only useful for bulk update. It might use CreateOrUpdateIP internally
package jsondb
import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	log "github.com/sirupsen/logrus"
	"github.com/netm4ul/netm4ul/core/config"
	"github.com/netm4ul/netm4ul/core/database/models"
	"github.com/netm4ul/netm4ul/core/security"
)
type JsonDB struct {
	cfg           *config.ConfigToml
	BaseDir       string
	RawPathFmt    string
	RawGlob       string
	ResultPathFmt string
	ProjectGlob   string
	UsersPath     string
}
func InitDatabase(c *config.ConfigToml) *JsonDB {
	j := JsonDB{}
	j.BaseDir = "./data"
	j.RawPathFmt = j.BaseDir + "/raw-%s-%s.json"
	j.RawGlob = j.BaseDir + "/raw-"
	j.ResultPathFmt = j.BaseDir + "/project-%s.json"
	j.ProjectGlob = j.BaseDir + "/project-*"
	j.UsersPath = j.BaseDir + "/users.json"
	j.cfg = c
	if _, err := os.Stat(j.BaseDir); os.IsNotExist(err) {
		os.Mkdir(j.BaseDir, 0755)
	}
	return &j
}
func (f *JsonDB) getRawPath(projectName, moduleName string) string {
	return fmt.Sprintf(f.RawPathFmt, projectName, moduleName)
}
func (f *JsonDB) getResultPath(projectName string) string {
	return fmt.Sprintf(f.ResultPathFmt, projectName)
}
func (f *JsonDB) Name() string {
	return "JsonDB"
}
func (f *JsonDB) writeURIs(projectName string, ip string, port string, uris []jsonURI) error {
	if projectName == "" {
		return errors.New("empty project name (writeURIs)")
	}
	if ip == "" {
		return errors.New("empty ip (writeURIs)")
	}
	if port == "" {
		return errors.New("empty port (writeURIs)")
	}
	portsFromFile, err := f.getPorts(projectName, ip)
	if err != nil {
		return err
	}
	found := 0
	var i int
	for i, p := range portsFromFile {
		if strconv.Itoa(int(p.Number)) == port {
			found = i
			p.URIs = uris
		}
	}
	if found > 0 {
		portsFromFile[i].URIs = append(portsFromFile[i].URIs, uris...)
	}
	return f.writePorts(projectName, ip, portsFromFile)
}
func (f *JsonDB) writePorts(projectName string, ip string, ports []jsonPort) error {
	if projectName == "" {
		return errors.New("empty project name (writePorts)")
	}
	if ip == "" {
		return errors.New("empty ip (writePorts)")
	}
	projectFromFile, err := f.getProject(projectName)
	if err != nil {
		return err
	}
	found := 0
	for i, ipFromFile := range projectFromFile.IPs {
		if ipFromFile.Value == ip {
			ipFromFile.Ports = ports
			found = i
		}
	}
	if found == 0 {
		projectFromFile.IPs[found].Ports = append(projectFromFile.IPs[found].Ports, ports...)
	}
	return f.writeProjects([]jsonProject{projectFromFile})
}
func (f *JsonDB) writeProjects(projects []jsonProject) error {
	for _, p := range projects {
		f.writeProject(p)
	}
	return nil
}
func (f *JsonDB) writeProject(project jsonProject) error {
	file, err := f.openResultFile(project.Name)
	if err != nil {
		return errors.New("Could not open result files : " + err.Error())
	}
	err = json.NewEncoder(file).Encode(project)
	if err != nil {
		return errors.New("Could not encode this project : " + err.Error())
	}
	return nil
}
func (f *JsonDB) writeUser(user jsonUser) error {
	users, err := f.getUsers()
	if err != nil {
		return errors.New("Could not write user : " + err.Error())
	}
	var usersMap map[string]jsonUser
	usersMap = make(map[string]jsonUser, 0)
	for _, u := range users {
		usersMap[u.Name] = u
	}
	usersMap[user.Name] = user
	file, err := os.OpenFile(f.UsersPath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		return errors.New("Could not open file : " + err.Error())
	}
	defer file.Close()
	err = json.NewEncoder(file).Encode(usersMap)
	if err != nil {
		return errors.New("Could not save json : " + err.Error())
	}
	return nil
}
func (f *JsonDB) writeRaw(file *os.File, r jsonRaws) error {
	log.Debugf("r : %+v", r)
	if r.ProjectName == "" {
		return errors.New("empty project (writeRaw)")
	}
	raws, err := f.getRaws(r.ProjectName)
	if err != nil {
		return errors.New("Could not getRaws for the project name : " + err.Error())
	}
	raws = append(raws, r)
	err = json.NewEncoder(file).Encode(raws)
	if err != nil {
		return err
	}
	file.Close()
	return nil
}
func (f *JsonDB) openRawFile(project, module string) (*os.File, error) {
	if project == "" {
		return nil, errors.New("empty project name (openRawFile)")
	}
	if module == "" {
		return nil, errors.New("empty module name (openRawFile)")
	}
	file, err := os.OpenFile(f.getRawPath(project, module), os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return file, nil
}
func (f *JsonDB) openResultFile(project string) (*os.File, error) {
	if project == "" {
		return nil, errors.New("empty project name")
	}
	file, err := os.OpenFile(f.getResultPath(project), os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return file, nil
}
func (f *JsonDB) SetupDatabase() error {
	log.Debugf("SetupDatabase jsondb")
	return errors.New("Not implemented yet")
}
func (f *JsonDB) DeleteDatabase() error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) SetupAuth(username, password, dbname string) error {
	return nil
}
func (f *JsonDB) Connect(c *config.ConfigToml) error {
	return nil
}
func (f *JsonDB) CreateOrUpdateUser(user models.User) error {
	var u jsonUser
	u.FromModel(user)
	err := f.writeUser(u)
	if err != nil {
		return errors.New("Could not create or update user : " + err.Error())
	}
	return nil
}
func (f *JsonDB) CreateUser(user models.User) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) UpdateUser(user models.User) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) getUsers() ([]jsonUser, error) {
	var users map[string]jsonUser
	usersArr := []jsonUser{}
	file, err := os.OpenFile(f.UsersPath, os.O_RDONLY|os.O_CREATE, 0755)
	if err != nil {
		return nil, errors.New("Could not open file : " + err.Error())
	}
	defer file.Close()
	err = json.NewDecoder(file).Decode(&users)
	if err == io.EOF {
		return usersArr, nil
	}
	if err != nil {
		return nil, errors.New("Could not decode file : " + f.UsersPath + ", error : " + err.Error())
	}
	for _, u := range users {
		usersArr = append(usersArr, u)
	}
	return usersArr, nil
}
func (f *JsonDB) GetUsers() ([]models.User, error) {
	usersModel := []models.User{}
	users, err := f.getUsers()
	if err != nil {
		return nil, err
	}
	for _, user := range users {
		usersModel = append(usersModel, user.ToModel())
	}
	return usersModel, nil
}
func (f *JsonDB) getUser(username string) (jsonUser, error) {
	users, err := f.getUsers()
	if err != nil {
		return jsonUser{}, err
	}
	for _, user := range users {
		if user.Name == username {
			return user, nil
		}
	}
	return jsonUser{}, nil
}
func (f *JsonDB) GetUser(username string) (models.User, error) {
	user, err := f.getUser(username)
	if err != nil {
		return models.User{}, err
	}
	return user.ToModel(), nil
}
func (f *JsonDB) GetUserByToken(token string) (models.User, error) {
	users, err := f.getUsers()
	if err != nil {
		return models.User{}, err
	}
	for _, user := range users {
		if user.Token == token {
			return user.ToModel(), nil
		}
	}
	return models.User{}, nil
}
func (f *JsonDB) GenerateNewToken(user models.User) error {
	user.Token = security.GenerateNewToken()
	err := f.CreateOrUpdateUser(user)
	if err != nil {
		return errors.New("Could not generate a new token : " + err.Error())
	}
	return nil
}
func (f *JsonDB) DeleteUser(user models.User) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) CreateOrUpdateProject(project models.Project) error {
	log.Debug("Create Project !")
	jp := jsonProject{}
	jp.FromModel(project)
	return f.createOrUpdateProject(jp)
}
func (f *JsonDB) CreateProject(project models.Project) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) UpdateProject(project models.Project) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) createOrUpdateProject(project jsonProject) error {
	projects, err := f.getProjects()
	if err != nil {
		return err
	}
	found := false
	for _, p := range projects {
		if p.Name == project.Name {
			found = true
			p = project
			break
		}
	}
	if !found {
		projects = append(projects, project)
	}
	return f.writeProjects(projects)
}
func (f *JsonDB) getProjects() ([]jsonProject, error) {
	var project jsonProject
	projects := []jsonProject{}
	files, err := filepath.Glob(f.ProjectGlob)
	if err != nil {
		return nil, err
	}
	log.Debugf("Read projects files : %+v", files)
	for _, filePath := range files {
		file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0755)
		if err != nil {
			log.Errorf("Could not open file : %s [err : %s]", filePath, err.Error())
			return nil, errors.New("Could not open file : " + err.Error())
		}
		defer file.Close()
		err = json.NewDecoder(file).Decode(&project)
		if err != nil {
			if err == io.EOF {
				log.Infof("Empty file %s", filePath)
				continue
			}
			return nil, errors.New("Could not decode file : " + err.Error())
		}
		projects = append(projects, project)
	}
	return projects, nil
}
func (f *JsonDB) GetProjects() ([]models.Project, error) {
	projectsModel := []models.Project{}
	projects, err := f.getProjects()
	if err != nil {
		return nil, err
	}
	for _, p := range projects {
		projectsModel = append(projectsModel, p.ToModel())
	}
	return projectsModel, nil
}
func (f *JsonDB) getProject(projectName string) (jsonProject, error) {
	projects, err := f.getProjects()
	if err != nil {
		return jsonProject{}, errors.New("Could not get projects list : " + err.Error())
	}
	for _, p := range projects {
		if p.Name == projectName {
			return p, nil  
		}
	}
	return jsonProject{}, nil
}
func (f *JsonDB) GetProject(projectName string) (models.Project, error) {
	project, err := f.getProject(projectName)
	if err != nil {
		return models.Project{}, err
	}
	return project.ToModel(), nil
}
func (f *JsonDB) DeleteProject(project models.Project) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) CreateOrUpdateIP(projectName string, ip models.IP) error {
	project, err := f.getProject(projectName)
	if err != nil {
		if err.Error() == "not found" {
			log.Infof("Creating file for project %s", projectName)
			f.openResultFile(projectName)
			p := jsonProject{}
			p.Name = projectName
			ipJson := jsonIP{}
			ipJson.FromModel(ip)
			p.IPs = []jsonIP{ipJson}
			err = f.writeProject(p)
			if err != nil {
				return errors.New("Could not save project : " + projectName)
			}
			return nil
		}
		return errors.New("Could not get project " + projectName + "," + err.Error())
	}
	found := false
	ipj := jsonIP{}
	ipj.FromModel(ip)
	for _, ipFromFile := range project.IPs {
		if ipFromFile.Value == ip.Value {
			ipFromFile = ipj
			found = true
			break
		}
	}
	if !found {
		project.IPs = append(project.IPs, ipj)
	}
	err = f.writeProject(project)
	if err != nil {
		return errors.New("Could not write project " + projectName + " : " + err.Error())
	}
	return nil
}
func (f *JsonDB) CreateIP(project string, ip models.IP) error {
	return errors.New("Not implemented yet")
}
func (f *JsonDB) UpdateIP(project string, ip models.IP) error {
	return errors.New("Not implemented yet")
}