<commit_before>package homecloud

import (
	"fmt"
	"reflect"
	"sync"
	"time"

	"code.google.com/p/go-uuid/uuid"
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/redigo/redis"
)

type ThingModel struct {
	baseModel
}

func toThing(obj interface{}) *model.Thing {
	var thing, ok = obj.(*model.Thing)
	if !ok {
		spew.Dump("BAD THING", obj)
		panic("Non-'Thing' passed to a ThingModel handler")
	}
	return thing
}

func NewThingModel(pool *redis.Pool, conn *ninja.Connection) *ThingModel {

	thingModel := &ThingModel{}
	thingModel.baseModel = baseModel{
		syncing: &sync.WaitGroup{},
		pool:    pool,
		idType:  "thing",
		objType: reflect.TypeOf(model.Thing{}),
		conn:    conn,
		log:     logger.GetLogger("ThingModel"),
		afterSave: func(obj interface{}) error {
			return thingModel.afterSave(toThing(obj))
		},
		afterDelete: func(obj interface{}) error {
			return thingModel.afterDelete(toThing(obj))
		},
		onFetch: func(obj interface{}, syncing bool) error {
			return thingModel.onFetch(toThing(obj), syncing)
		},
	}
	return thingModel
}

func (m *ThingModel) ensureThingForDevice(device *model.Device) error {

	// It was a new device, we might need to make a thing for it
	thing, err := thingModel.FetchByDeviceId(device.ID)

	if err != nil && err != RecordNotFound {
		// An actual error
		return err
	}

	if thing != nil {
		// A thing already exists
		return nil
	}

	log.Debugf("Device %s has no thing. Creating one", device.ID)

	thing = &model.Thing{
		DeviceID: &device.ID,
		Name:     "New Thing",
		Type:     "unknown",
	}

	if device.Signatures != nil {
		thingType, hasThingType := (*device.Signatures)["ninja:thingType"]

		if hasThingType {
			thing.Type = thingType
			if device.Name == nil {
				thing.Name = "New " + thingType
			}
		}
	}

	if device.Name != nil {
		thing.Name = *device.Name
	}

	return thingModel.Create(thing)
}

func (m *ThingModel) Create(thing *model.Thing) error {
	m.syncing.Wait()
	//defer m.sync()

	if thing.ID == "" {
		thing.ID = uuid.NewUUID().String()
	}

	_, err := m.save(thing.ID, thing)

	return err
}

func (m *ThingModel) afterSave(thing *model.Thing) error {

	conn := m.pool.Get()
	defer conn.Close()

	m.log.Debugf("afterSave - thing received id:%s with device:%s", thing.ID, *thing.DeviceID)

	existingDeviceID, err := m.getDeviceIDForThing(thing.ID)

	if err != nil && err != RecordNotFound {<commit_msg>Fix for nil pointer panic in Thing.afterSave<commit_after>package homecloud

import (
	"fmt"
	"reflect"
	"sync"
	"time"

	"code.google.com/p/go-uuid/uuid"
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/redigo/redis"
)

type ThingModel struct {
	baseModel
}

func toThing(obj interface{}) *model.Thing {
	var thing, ok = obj.(*model.Thing)
	if !ok {
		spew.Dump("BAD THING", obj)
		panic("Non-'Thing' passed to a ThingModel handler")
	}
	return thing
}

func NewThingModel(pool *redis.Pool, conn *ninja.Connection) *ThingModel {

	thingModel := &ThingModel{}
	thingModel.baseModel = baseModel{
		syncing: &sync.WaitGroup{},
		pool:    pool,
		idType:  "thing",
		objType: reflect.TypeOf(model.Thing{}),
		conn:    conn,
		log:     logger.GetLogger("ThingModel"),
		afterSave: func(obj interface{}) error {
			return thingModel.afterSave(toThing(obj))
		},
		afterDelete: func(obj interface{}) error {
			return thingModel.afterDelete(toThing(obj))
		},
		onFetch: func(obj interface{}, syncing bool) error {
			return thingModel.onFetch(toThing(obj), syncing)
		},
	}
	return thingModel
}

func (m *ThingModel) ensureThingForDevice(device *model.Device) error {

	// It was a new device, we might need to make a thing for it
	thing, err := thingModel.FetchByDeviceId(device.ID)

	if err != nil && err != RecordNotFound {
		// An actual error
		return err
	}

	if thing != nil {
		// A thing already exists
		return nil
	}

	log.Debugf("Device %s has no thing. Creating one", device.ID)

	thing = &model.Thing{
		DeviceID: &device.ID,
		Name:     "New Thing",
		Type:     "unknown",
	}

	if device.Signatures != nil {
		thingType, hasThingType := (*device.Signatures)["ninja:thingType"]

		if hasThingType {
			thing.Type = thingType
			if device.Name == nil {
				thing.Name = "New " + thingType
			}
		}
	}

	if device.Name != nil {
		thing.Name = *device.Name
	}

	return thingModel.Create(thing)
}

func (m *ThingModel) Create(thing *model.Thing) error {
	m.syncing.Wait()
	//defer m.sync()

	if thing.ID == "" {
		thing.ID = uuid.NewUUID().String()
	}

	_, err := m.save(thing.ID, thing)

	return err
}

func (m *ThingModel) afterSave(thing *model.Thing) error {

	conn := m.pool.Get()
	defer conn.Close()

	m.log.Debugf("afterSave - thing received id:%s with device:%s", thing.ID, thing.DeviceID)

	existingDeviceID, err := m.getDeviceIDForThing(thing.ID)

	if err != nil && err != RecordNotFound {
{'fraction_non_alphanumeric': 0.14631245043616178, 'fraction_numerical': 0.0, 'mean_word_length': 3.7149532710280373, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2190781', 'n_tokens_mistral': 1998, 'n_tokens_neox': 1862, 'n_words': 424}