spotlight-network-v1 0.0.1
Create a network of groups of instances (some kind of lists). Those groups interact with each other.
Requires Python: >=3.6

The Spotlight-Workspace :
=========================

### Introduction :
That package provides several tools that require to be combined to really be useful.
The ultimate purpose of those combinations is to create a "network". As "primitive nodes" of that network we have Spotlights that can be considered as some kind of lists. Those Spotlights represent a group / a selection. The other tools of the package are mainly made to make the content of those Spotlights automatically updated. To do so we will create some LightRules. From there the light of the Spotlight will be partially or totally dynamically defined. A basic kind of Rule is to connect a Spotlight to other ones. This is why we are talking about a network. Connecting spotlights together can, for instance, define that the light of a Spotlight depends on the light of another Spotlight.

Spotlight :
=========

### Introduction :
A way to "group" instances, in the same way that a list or a set.
The differences with these types are :

* Spotlights are designed to be a part of a workspace. You should not use a vanilla Spotlight.
* Spotlights are supposed to represent a "selection". Most of the time, it should only contains instances of a same other container (a list, a set, a Qt Model, ...)
* Spotlights emit PyQt signals when the light of instances change.

### Role :
On its own a Spotlight doesn't provide a lot of value compared to a list. The only noticeable difference would be that Spotlights emit PyQt signals when the light change.


### Usage :
Spotlight are designed to be used through an ExpandedSpotlightSystem. Do not use vanilla Spotlights.

ExpandedSpotlightSystem :
=======================

### Role :
Based on a core Spotlight, create a way to make it's light dynamically defined. To do so it requires you to implements some "LightCheckers". Each of those checkers will define that instances of the core Spotlight should be light if a given condition is respected.

### Destructive & not-destructive systems:
There are 2 types of systems. The first one will directly edit the core Spotlight will the other will create a new Spotlight. The light of that Spotlight will merge the light of the core Spotlight and light created by LightCheckers. In that case the result Spotlight is a MergedSpotlight.

**Destructive Systems are not maintained anymore ! Use only not-destructive one**.

### PotentialInstances :
When you know that some instances might by lighted by a Spotlight, it's a good practice to declare it. Some Checkers might optimize themselves if they have that information and some might actually not work without that information. Generally, if you can declare it, do it. However, keep in mind that potential instances **doesn't necessary includes every lightable instances !** You can light an instance even if it's not declared as a potential instance !

LightRule :
===========

### Role :
From a rule instance, you can ask if an instance is supposed to be in light. Basically it can be summaries as a wrapper for an if statement. Most of the time, the only method of the rule that will be used will be a "defineInstanceLight".

### SpotlightA2B & SpotlightX2B rules :
Even if it's not always the case, LightRules often define the light of instances based on the light of one or more other Spotlights. This is why we often speak about a "Spotlight-network" : Spotlights are connected together.

Those connections are made by rules.

There are 2 type of those connections : "A2B" and "X2B". In the first case the light of a Spotlight "B" relies on the light of another Spotlight "A". So we will always look at the same other Spotlight to define if an instance must be in light in another Spotlight. On the other hand, an X2B connection will look at several other Spotlights. In other words, with an "A2B", the Spotlight "B" is connected to the Spotlight "A" while with the "X2B", each instances of the Spotlight "B" is connected to another Spotlight.

### Usage :
Rules are designed to be used through a LightChecker. Do not use vanilla Rules.

DynamicLightChecker :
===========

### Role :
The way to dynamically be aware if the light of an instance should have change. ExpandedSpotlightSystem use those Checkers to know when the light of the Spotlight must be changed.
So to summary, a Checker is just an instance that emit signals to warn that an instance must be lighted. Nothing more.

### Checker vs Rules :
The difference between those two instances type can be confusing. They actually do both have the same main method "defineInstanceLight". In fact a Checker use one or more Rules. The main differences are :
* Checkers are QObjects.
* Checkers are "dynamic" : When something append, it will know that the light of some instances might have change.
* Generally checkers are "Lazy" : It will only check the light of instances if it considers that the light of it might have change compared to the last time it has been checked.

### Implementation :
In fact, implementing a Checker is equivalent to just implementing a PyQt signal handler. When something(s) append (one or more PyQt signal(s) is/are emitted), check if the light of some instances should be changed. If it actually should, emit some signals to say it. Those signals should be handled by The ExpandedSpotlightSystem.

### Checker from Rule :
From your Rule you should create a Checker. To do so, you must pick the appropriate Checker type :
* **ABS_SpotlightA2B_LightRule_ByMapping** : Use a _A2B_ByMapping_LazyDynamicLightChecker_
* **SpotlightX2B_LightRule_ByExhaustState** : Use a _X2B_ByExhaustState_LazyDynamicLightChecker_
* **Other kind of Rule** : In that case, you must create a _specific Checker_.

### Usage :
With Checker that relies on a A2B-Rule, it's pretty straightforward. Just create the Checker with required arguments should do it. Your Checker is ready and must start emitting event when necessary. With X2B-Rules it's a little more tricky. For each instance of the B-Spotlight, you need to declare the X-Spotlight bound. This is made by manually calling methods of the Checker.


MultiDynamicLightCheckers :
-------------------

### Role:
The same that DynamicLightChecker except that this one will merge the result of several Checkers. There are several "modes" for those MultiCheckers. For instance, "OnlyOneLight" will define that an instance must be lighted if at least 1 sub Checker says that it must be lighted.


SpotlightNetwork :
================
There isn't any Network class. Each System has got some Checker that are themselves linked to some other Systems. The links created are directional : there are parent Systems and child Systems. That chain of connections create a Network without an instance of the type Network.

### Navigation :
When navigating in a Network, you can only go down (find child System).
There are 2 ways to navigate. In any case, to start a navigation you need a System instance. From that instance you will be able to find child Systems of it. When you start a navigation, that System is named the "rootSystem".

## The explicit way (longer) :
* From the "rootSystem", you can grab one of its Checkers. The easier way it to use the method "findCheckerByType".
* From that Checker you can grab a child System. The method to do so will depend on your Checker type.
* You can use the same steps from that child System to go deeper.
* When you reached the System that you want, you can grab the Spotlight itself with the property "resultSpotlight".

## The implicit way (shorter) :
You can create a NetworkManipulator instance so make that process slightly shorter. A singleton of that class should be enough for your entire project. That instance will give you tools to go 1 step down in a single command. Notice that even with that way, navigation is still a verbose process.


MergedSpotlight :
=========
Merge the lighted instances of several Spotlights

### Usages :
For the most part it will work just as a classic Spotlight. However, you can not define the light of that Spotlight while it's actually a computed value. Change the light of merged Spotlights to do so.

Current issues :
================

### Bounding light chain :
Most of the time you want to light an instance in a System-a that will, by causality light an instance in a System-b. What you do not want is that when that light occurs in System-b, it also trigger another light in System-a.
The easier way to prevent it is to set the argument "onlyHardLight" to True on one of the Checkers that are involved in the chain.

Package architecture :
======================

### Suitcase and Supplies folders :
Suitcase folders contains tools that are not usable as it is. It includes interfaces, abstracts classes, etc. On the other hand, Supplies contains the "ready to use" classes.

NetworkDescriptor :
===================

A NetworkDescriptor mainly exists to explain to the computer what the Network is supposed to do. Some features require a Descriptor (mainly debug features).

Debugging :
===========

### Unit tests :

#### Test your Checkers :
You can inherit "ABS_GenericTest_Checker" or "ABS_GenericTest_GlobalLightChecker" to create some unit test to test your Checker.
Notice that when you inherit those class, you must delete the abstract class after implementing it ! read https://stackoverflow.com/questions/4566910/abstract-test-case-using-python-unittest/4566992

#### Test the complete Network :
There isn't any class to do so. Just testing all your Checkers should be enough. If you want to test more advanced features you will have to create your own implementation of unittest.TestCase.

### Displays the Network :
You can use a NetworkViewer to have a visual representation of your Network.
Notice that it will require to create a NetworkDescriptor.


Examples and usage :
========

You can find that example in Unittests of the package as ExampleTest_Book.

You have got the given classes :
* Book : Has a name and contains some BookPage instances.
* BookPage : Has a number and contains some Word instances.
* Word : Has a text.

From those classes you want to create a Network :
Notice that, for a similar result, there are several possibilities of Network. You should create the Network that will gives you the more appropriate Spotlights for your usage.
In the current case we can have :

## Several small Systems (the scattered way) :

#### Structure :

[Books-system] *X 1*

[Pages-system] *X n* (where *n* is the count of potential lighted books)

[Words-system] *X n* (where *n* is the count of potential lighted pages)

#### Description :
* In that Network we so have 1 BookSystem, more PageSystems and even more WordSystems.
* You can use GlobalLightRules that generally provides better CPU performances.

#### Advantages :
"X2B" rules might be more tricky to use. That approach prevent to use too much of them.

#### Checkers and Rules :
* When at least 1 Page of a Book is selected, the Book is also selected :
  * The "at least" means that we need an "exhaust state" rule.
  * The selection of each Book relies on a private spotlight of Pages (each Book doesn't have the same Pages). We so need a "X2B" rule.
* When at least 1 Word of a Page is selected, the Page is also selected :
  * The "at least" means that we need an "exhaust state" rule.
  * The selection of each Page relies on a private list of Words (each Page doesn't have the same Words). We so need a "X2B" rule.
* When a specific Book is selected, all its Pages are also selected :
  * The "all its" means that we need a "GlobalLightRule".
  * The "a specific" means that we need a "by mapping" rule.
  * Each PageSystem is linked to a single BookSystem. We so need a "A2B" rule. 
* When a specific Page is selected, all its Words are also selected.
  * The "a specific" means that we need a "by mapping" rule.
  * Each WordSystems is linked to a single PageSystem. We so need a "A2B" rule.
  
## 3 big Systems (the condensed way) :
[Books-system] *X 1*

[Pages-system] *X 1*

[Words-system] *X 1*

#### Description :
In that Network there are only 3 Systems.

#### Advantages :
* You will generally not have to use any X2B Rules that can be harder to use.
* Having fewer Systems can make your Network more simple. You can for instance create a Network class (remember that that kind of class doesn't exist in that framework). In that class you can store your Systems and have easy access to them. That kind of Network instance would not be realistically possible in a scattered Network which means to work with a Network with more Systems and also some X2B patterns (so an undefined count of Systems of the same type)

#### Disadvantages :
* When working with condensed Networks you will often have to deal with interdependencies.
A System-A have some Checkers that relies on another System-B.
That System-B also have some Checkers that relies on the System-A.
The first downside of it is that you will have to instantiate your Systems with "initMultiChecker" set to False.
When your both Systems are created you should be able to init Checkers.
* You almost never can use GlobalLightRules in a condensed Network.

##### Checkers and Rules :
* When at least 1 Page of a Book is selected, the Book is also selected :
    * The "at least" means that we need an "exhaust state" rule.
    * While we are working in that Network with only a single Spotlight for Pages, we need a A2B Rule.
    * As pattern for our A2B <Rule> by exhaust state, we need to check if the <Page> is a <Page> of the tested <Book>.

* When at least 1 Word of a Page is lighted, the page is also lighted.
  * The "at least" means that we need an "exhaust state" rule.
  * While we are working in that Network with only a single Spotlight for Words, we need a A2B Rule.
  * As pattern for our A2B Rule by exhaust state, we need to check if the Word is a <Word> of the tested <Page>.

* When a specific Book is selected, all its Pages are also selected :
  * All Pages of the PagesSystem must not be lighted when we light a specific Book. Only Pages of that Book should. So we can not use a GlobalLightRule that are made to light all instances managed by a System. Instead we have to use a basic SingleLightRule.
  * The "a specific" means that we need a "by mapping" Rule.
  * There is only 1 PagesSystem in that Network so we need a "A2B" Rule.

* When a specific Page is selected, all its Words are also selected :
  * All Words of the WordsSystem must not be lighted when we light a specific Page. Only Words of that Page should. So we can not use a GlobalLightRule that are made to light all instances managed by a System. Instead we have to use a basic SingleLightRule.
  * The "a specific" means that we need a "by mapping" Rule.
  * There is only 1 WordsSystem in that Network so we need a "A2B" Rule.