# Manifest Service

The Manifest service (powered by [manyfest](https://github.com/stevenvelozo/manyfest)) provides object navigation and manipulation using hash/address paths, supporting complex data access patterns.

## Access

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });

// On-demand service - instantiate when needed
const manifestService = fable.instantiateServiceProvider('Manifest');
console.log('manifestService:', typeof manifestService);

// Or use the factory method (creates unregistered instance)
const manifestEmpty = fable.newManyfest();
console.log('manifestEmpty:', typeof manifestEmpty);

// With definition
const manifestDefined = fable.newManyfest({
    Scope: 'User',
    Descriptors: {
        'Name':  { Hash: 'name',  Type: 'String' },
        'Email': { Hash: 'email', Type: 'String' }
    }
});
console.log('manifestDefined scope:', manifestDefined.scope);
```

## Core Concepts

### Hash/Address Notation

Navigate objects using dot-notation paths:

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const obj = {
    user: {
        profile: {
            name: 'John',
            contacts: [
                { type: 'email', value: 'john@example.com' }
            ]
        }
    }
};

console.log(manifest.getValueByHash(obj, 'user.profile.name'));           // 'John'
console.log(manifest.getValueByHash(obj, 'user.profile.contacts[0].value')); // 'john@example.com'
```

## Getting Values

### getValueByHash

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = { a: { b: { c: 'value' } } };

console.log(manifest.getValueByHash(data, 'a.b.c'));     // 'value'
console.log(manifest.getValueByHash(data, 'a.b'));       // { c: 'value' }
console.log(manifest.getValueByHash(data, 'x.y.z'));     // undefined
```

### With Default Value

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = { a: 'present' };
console.log(manifest.getValueByHash(data, 'missing.path', 'default'));  // 'default'
```

### Array Access

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = { items: ['a', 'b', 'c'] };

console.log(manifest.getValueByHash(data, 'items[0]'));  // 'a'
console.log(manifest.getValueByHash(data, 'items[2]'));  // 'c'
```

## Setting Values

### setValueByHash

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = {};

manifest.setValueByHash(data, 'user.name', 'John');
console.log('After name set:', data);

manifest.setValueByHash(data, 'user.age', 30);
console.log('After age set:', data);
```

### Creating Nested Structures

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = {};
manifest.setValueByHash(data, 'deep.nested.path.value', 'hello');
console.log('data:', data);
// Creates: { deep: { nested: { path: { value: 'hello' } } } }
```

### Array Setting

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = { items: [] };
manifest.setValueByHash(data, 'items[0]', 'first');
manifest.setValueByHash(data, 'items[1]', 'second');
console.log('data.items:', data.items);
```

## Checking Existence

### checkAddressExists

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = { a: { b: 'value' } };

console.log(manifest.checkAddressExists(data, 'a.b'));      // true
console.log(manifest.checkAddressExists(data, 'a.c'));      // false
console.log(manifest.checkAddressExists(data, 'x.y.z'));    // false
```

## Manifest Definitions

Define schemas for structured data:

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });

const userManifest = fable.newManyfest({
    Scope: 'User',
    Descriptors: {
        'Full Name': {
            Hash: 'profile.fullName',
            Type: 'String',
            Default: 'Unknown'
        },
        'Age': {
            Hash: 'profile.age',
            Type: 'Number',
            Default: 0
        },
        'Email': {
            Hash: 'contact.email',
            Type: 'String'
        },
        'Active': {
            Hash: 'status.isActive',
            Type: 'Boolean',
            Default: true
        }
    }
});

console.log('userManifest descriptors:', Object.keys(userManifest.elementDescriptors));
```

### Using Descriptors

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });

const userManifest = fable.newManyfest({
    Scope: 'User',
    Descriptors: {
        'Full Name': { Hash: 'profile.fullName', Type: 'String', Default: 'Unknown' },
        'Age':       { Hash: 'profile.age',      Type: 'Number', Default: 0 },
        'Email':     { Hash: 'contact.email',    Type: 'String' },
        'Active':    { Hash: 'status.isActive',  Type: 'Boolean', Default: true }
    }
});

// Get all descriptor names
const names = userManifest.getDescriptorNames();
console.log('names:', names);

// Get descriptor by name
const emailDescriptor = userManifest.getDescriptor('Email');
console.log('emailDescriptor:', emailDescriptor);
```

## Boxed Properties

Access properties with special characters using brackets:

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });
const manifest = fable.instantiateServiceProvider('Manifest');

const data = {
    'my-special-key': 'value1',
    'another key': 'value2'
};

console.log(manifest.getValueByHash(data, '["my-special-key"]'));   // 'value1'
console.log(manifest.getValueByHash(data, "['another key']"));     // 'value2'
```

## Use Cases

### Dynamic Form Handling

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });

function updateFormData(formData, fieldPath, value) {
    const manifest = fable.newManyfest();
    manifest.setValueByHash(formData, fieldPath, value);
    return formData;
}

// Usage
let form = {};
form = updateFormData(form, 'user.firstName', 'John');
form = updateFormData(form, 'user.lastName', 'Doe');
form = updateFormData(form, 'user.address.city', 'New York');

console.log('form:', form);
```

### Configuration Access

```javascript
const libFable = require('fable');
const fable = new libFable({
    Product: 'ManifestDemo',
    API:     { timeout: 5000 },
    Logging: { debug: true }
});

function getConfig(path, defaultValue) {
    const manifest = fable.newManyfest();
    return manifest.getValueByHash(fable.settings, path, defaultValue);
}

// Usage
const timeout = getConfig('API.timeout', 30000);
const debug   = getConfig('Logging.debug', false);
console.log('timeout:', timeout, 'debug:', debug);
```

### Data Transformation

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });

function transformData(source, mappings) {
    const manifest = fable.newManyfest();
    const result = {};

    Object.entries(mappings).forEach(([targetPath, sourcePath]) => {
        const value = manifest.getValueByHash(source, sourcePath);
        if (value !== undefined) {
            manifest.setValueByHash(result, targetPath, value);
        }
    });

    return result;
}

// Usage
const apiResponse = {
    data: { user: { name: 'Alice', contact: { email: 'alice@example.com' } } },
    metadata: { created: '2024-01-01' }
};
const transformed = transformData(apiResponse, {
    'userName':  'data.user.name',
    'userEmail': 'data.user.contact.email',
    'createdAt': 'metadata.created'
});
console.log('transformed:', transformed);
```

### Safe Property Access

```javascript
const libFable = require('fable');
const fable = new libFable({ Product: 'ManifestDemo', ProductVersion: '1.0.0' });

function safeGet(obj, path, defaultValue = null) {
    const manifest = fable.newManyfest();
    const value = manifest.getValueByHash(obj, path);
    return value !== undefined ? value : defaultValue;
}

// Safely access deeply nested properties
const user = { address: { city: 'NYC' }, contacts: [] };
const city  = safeGet(user, 'address.city',         'Unknown');
const phone = safeGet(user, 'contacts[0].phone',    'N/A');
console.log('city:', city, 'phone:', phone);
```

## Integration with Other Services

The Manifest service is used internally by:
- `Utility.getValueByHash()`
- `Utility.setValueByHash()`
- Math service for object set operations
- Expression parser for variable resolution

## Notes

- Paths are case-sensitive
- Non-existent intermediate objects are created automatically when setting
- Array indices use bracket notation: `items[0]`
- Special characters in keys require bracket notation with quotes
