'''
------------------------
2022-07-13 Release


------------------------
 Recipe 1 To-Do list
------------------------
cafm = cumulative affine matrix

To do:
[x] jump to functionality
[x] re-generate aligned
[] project class
[x] widgets for controls become hidden or visible as user progresses through project
[x] make menu bar attached on macOS
[x] after selecting 'skip', it should not be necessary to re-focus on images widget
[] spawn new thread for making Zarr, to not lock up the GUI
[x] improve affine combo box for intuitive/automatic control flow
[x] automatically focus back on ZoomPanWidget after adjusting control panel
[] when skips are reset, remove red 'x' annotation immediately
[] display current affine more clearly
[x] enable multithreaded export to Zarr
[] run make_zarr.py in a separate thread
[] make_zarr.py 'Cancel' functionality
[] make_zarr.py UI configuration option for when Zarr exists at current scale. whether to (a) cancel (b) overwrite (c) ask
[] BUG: when Keep/Toggle switch is used pre-scaling, red X does not appear immediately
[] improved robustness in error recovery of task_queue
[] generate error report logs, save inside project (talk to James about saving log files to remote database/server)
[] ask to save before exiting
[x] set project destination instantly upon re-opening a project
[] dim out "#scales" and "clevel" when compression combobox option "none" is selected
[] cancel Zarr export
[x] check if aligned images exist before exporting to Zarr. Cancel and display warning otherwise.
[] if-and-only-if quitting without a recent save, have option to save first
[] call 'Apply Affine' something more descriptive, or make its function more clear ('Force Affine'?)
[] add a place to take notes (see: https://pythonbasics.org/pyqt-menubar/)
[x] should be able to export aligned to Zarr at any scale
[x] project status indicator
[] there should ALWAYS be a scale 1, not just when scales are generated
[] underlined letters for hotkeys
[] forget/remove all images from project function
[] if scales exist, ask user if they are sure they want to RE-generate alignment (possibly overwriting something they worked hard on)
[] "would you like to create a new project with these images or add them to the current stack?"
[] SNR reported differently between ref, base, and aligned
[] add back make functionality for view mode (View or Crop)  view_match_crop = ComboBoxControl(['View', 'Match', 'Crop'])
[x] add functionality back for alignem.project_data['data']['scales'][prev_scale_key]['null_cafm_trends'] = False
[x] add functionality back for alignem.project_data['data']['scales'][prev_scale_key]['poly_order'] = int(0)
[x] add functionality back for alignem.project_data['data']['scales'][prev_scale_key]['use_bounding_rect'] = False
[x] upgrade PySide2 (Qt5) to PySide6 (Qt6)
[x] upgrade Daisy from v0.2 to v1.0
[x] spawn new thread for emdedded web browser
[x] embed neuroglancer viewer
[x] embed documentation
[x] remake control panel using more conventional and scalable Python/Qt strategies
[x] implement QStackedWidget to allow the application to have paging, replete with back buttons, etc.
[x] apply stylesheet
[x] replace 'skip' checkbox with toggle button
[x] automatically center images after (a) importing images (b) generating scales (c) generating alignments
[x] move align_all_or_some to its own script
[x] fix scale combo box text i.e. scale_1 -> Scale 1
[] max bounding box size threshold
[] have a default project name for new projects, i.e. 'my_project.json'
[x] put a stop to the gray rectangle bug
[x] fix bug that requires a project to be saved
[] Tool Tips for all/most buttons/menus
[] auto-generate images button in primary alignment control panel
[x] 'apply to all' button for whitening and SWIM window
[] toggle for auto-generate images
[x] function to check if source images have been imported
[x] function to check how many source images have been imported
[x] faster loading of large images
[x] Would you like to save before exiting?
[] Refactor 'set_scales_from_string' functionality (two callers: 'new_project', 'generate_scales_queue')
[] 'areImagesCentered' function
[x] set_default_settings cannot be a member function of main_window. This is not data driven.
[] Save Automatically toggle switch
[] project has unsaved changes flag (similar to what Tom does)... for asking user whether to save before exit
[x] Show which scales have been aligned (possibly with non-selectable radio boxes)
[] SWIM Window <- # of pixels in label
[] show SWIM window as overlay on base & ref
[] for new project, there could be an issue with set_default_settings() func
[] bug where when project is saved on first base image in the stack (which has no ref) -> reopening the project and changing layer will require a re-center
[x] fix SNR image hover tooltips
[x] fix makefile.linux
[x] make a better README.txt, add list of packages
[] test everything on Ubuntu
[] add check for c binaries at startup -> else quit application
[x] mouseover-specific tooltips or status information

Important For Launch:
[x] scaling with iscale, for neuroglancer/zarr
[] extend support for with rectangular images
[x] match-point functionality
[] cropping functionality
[] project directory validator
[] ZOOM
[] SWIM randomly misfires
[] hide skipped images
[] dim out skipped images instead of red 'X'
[] magnifying glass
[] use QSplitter for showing additional status info/project details
[] view or hide skipped images
[] align just one

Things project_data should probably include:
* is project scaled (bool)
* scales with alignments so-far generated (list of strings, i.e. ['scale_4', 'scale_2'])

To do (Zarr/precomputed):
[x] look into making pre-computed format multithreaded
[x] look into Zarr directory store
[] insert/remove images from Zarr (callback functions)


''''''
------------------------
 Recipe 2 To-Do list
------------------------
[] match-point mode



TESTING THE FOLLOWING IN MENU
self.update_win_self()
self.update_panels()
self.refresh_all_images
    * only refresh_all_images updated the display with current scale


inspect module doc:
https://docs.python.org/3/library/inspect.html

print calling function with inspect module:
print(inspect.stack()[1].function)
 "Caller: " + inspect.stack()[1].function
 Caller: ' + inspect.stack()[1].function + ' |


ZoomPanWidget.get_settings
ZoomPanWidget.update_zpa_self



Check if scales have been generated yet:
len(project_data['data']['scales']) = 2
if len(project_data['data']['scales']) > 0:


Print/return the number of aligned images in  <project destination>/<current scale>/img_aligned

dir = os.path.join(project_data['data']['destination_path'], get_cur_scale_key(), 'img_aligned')
print(len([name for name in os.listdir(dir) if os.path.isfile(os.path.join(dir, name))]))


zooming issue...
qt.pointer.dispatch: delivering touch release to same window QWindow(0x0) not QWidgetWindow(0x7f8454c9aef0, name="MainWindowClassWindow")
qt.pointer.dispatch: skipping QEventPoint(id=1 ts=0 pos=0,0 scn=858.668,722.959 gbl=858.668,722.959 Released ellipse=(1x1 ∡ 0) vel=0,0 press=-858.668,-722.959 last=-858.668,-722.959 Δ 858.668,722.959) : no target window
qt.pointer.dispatch: delivering touch release to same window QWindow(0x0) not QWidgetWindow(0x7f8454c9aef0, name="MainWindowClassWindow")
qt.pointer.dispatch: skipping QEventPoint(id=1 ts=0 pos=0,0 scn=1096.8,909.006 gbl=1096.8,909.006 Released ellipse=(1x1 ∡ 0) vel=0,0 press=-1096.8,-909.006 last=-1096.8,-909.006 Δ 1096.8,909.006) : no target window
js: performance warning: READ-usage buffer was written, then fenced, but written again before being read back. This discarded the shadow copy that was created to accelerate readback.
qt.pointer.dispatch: delivering touch release to same window QWindow(0x0) not QWidgetWindow(0x7f8454c9aef0, name="MainWindowClassWindow")
qt.pointer.dispatch: skipping QEventPoint(id=4 ts=0 pos=0,0 scn=1089.21,802.695 gbl=1089.21,802.695 Released ellipse=(1x1 ∡ 0) vel=0,0 press=-1089.21,-802.695 last=-1089.21,-802.695 Δ 1089.21,802.695) : no target window
qt.pointer.dispatch: delivering touch release to same window QWindow(0x0) not QWidgetWindow(0x7f8454c9aef0, name="MainWindowClassWindow")
qt.pointer.dispatch: skipping QEventPoint(id=1 ts=0 pos=0,0 scn=1418.85,903.845 gbl=1418.85,903.845 Released ellipse=(1x1 ∡ 0) vel=0,0 press=-1418.85,-903.845 last=-1418.85,-903.845 Δ 1418.85,903.845) : no target window

This bug could have to do with unused lines of code related to focus, i.e. self.setFocusPolicy(Qt.StrongFocus) #jy #focus

This issue appears to be linked to TensorFlow
https://github.com/tensorflow/tfjs/issues/1145


POSSIBLE WORKFLOW FOR VIEWING SINGLE BLEND IN NEUROGLANCER VIEWER
1. Create blended image
2. If project.zarr/img_blended_zarr group does not exist, create it
3. Converted blended image to Zarr using tiffs2zarr utility function (from glanceem_utils.py).
4. Blended image array is appended to project.zarr/img_blended_zarr
5. Neuroglancer viewer top panel is updated to display Zarr group img_blended_zarr


weird, this randomly appeared:
js: crbug/1173575, non-JS module files deprecated.



At the end of alignment, we have affine and cumulative affine for each image

Matrix decomposition


options for threading:
https://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt

Using a QRunnable
http://qt-project.org/doc/latest/qthreadpool.html
Note that a QRunnable isn't a subclass of QObject and therefore does
not provide signals and slots.

QWebSocketCorsAuthenticator¶
https://doc.qt.io/qtforpython/PySide6/QtWebSockets/QWebSocketCorsAuthenticator.html?highlight=cors

'''


Talk to Tom about globals, specifically 'global_swiftir_mode' see: 'pyswift_tui' and 'align_swiftir' where it is hardcoded to 'python'