func main() {
	flag.Usage = usage
	flag.Parse()

	if *help {
		usage()
	}

	// Read the configuration
	c, err := config.ReadConfigFromFile(cfgfile, source)
	if err != nil {
		fmt.Printf("Error:: %v\n", err)
		os.Exit(0)
	}

	// Create a Process
	process := &Process{Done: make(chan bool),
		Source:         *source,
		Started:        true,
		PagesFileInfo:  make(map[string]*os.FileInfo),
		AssetsFileInfo: make(map[string]*os.FileInfo),
	}

	// Create output directory if it does not exist
	err = os.Mkdir(c.OutputDirectory, 0755)

	// Generate whole book
	GenerateWholeBook(process)

	// Go into watch mode
	if *watchMode {
		WatchMode(*interval, process)
	}
}
func GenerateWholeBook(p *Process) error {
	// Get the parts of the config file
	sourcePath := config.SourcePath(source)
	// Set the config file name
	configFile := config.ConfigFile(sourcePath, cfgfile)
	// Log the attempt to read the configuration file
	log.Printf("Reading configuration file %s\n", configFile)
	// Read the configuration
	c, err := config.ReadConfigFromFile(cfgfile, source)
	if err != nil {
		fmt.Printf("Error:: %v\n", err)
		p.Done <- true
		return err
	}

	// Set the source path
	c.SourcePath = sourcePath

	// Process and generate the book
	log.Printf("Generating Book\n")
	err = GenerateBook(p, c)
	if err != nil {
		fmt.Printf("Error:: %v\n", err)
		p.Done <- true
		return err
	}

	return nil
}
func main() {
	flag.Usage = usage
	flag.Parse()

	if *help {
		usage()
	}

	// Read the configuration
	c, err := config.ReadConfigFromFile(cfgfile, source)
	HandleError(err)

	// Add the missing sourcePath
	c.SourcePath = *source

	// Create a Process
	process := &Process{Done: make(chan bool),
		Source:         *source,
		Started:        true,
		PagesFileInfo:  make(map[string]*os.FileInfo),
		AssetsFileInfo: make(map[string]*os.FileInfo),
	}

	// Create a plugin configuration object
	configPlugin := &gutenberg.PluginConfig{SourcePath: *source,
		OutputDirectory: c.OutputDirectory}
	// Get the custom HTML transformer
	process.CustomTransformer = gutenberg.NewCustomHtml(c)
	// Add new Custom Plugins to the transformer
	process.CustomTransformer.AddPlugin("dot", plugins.NewDotPlugin(configPlugin))
	process.CustomTransformer.AddPlugin("note", plugins.NewNotePlugin())

	// Create output directory if it does not exist
	err = os.Mkdir(c.OutputDirectory, 0755)

	// Rebuild the entire book
	if *rebuild {
		GenerateWholeBook(process)
	} else {
		HandleError(ReadAllModTimes(c, process))
	}

	// Go into watch mode
	if *watchMode {
		WatchMode(*interval, process)
	}
}
func ReadConfiguration(p *Process) (*config.Config, error) {
	// Get the parts of the config file
	sourcePath := config.SourcePath(source)
	// Set the config file name
	configFile := config.ConfigFile(sourcePath, cfgfile)
	// Log the attempt to read the configuration file
	log.Printf("Reading configuration file %s\n", configFile)
	// Read the configuration
	c, err := config.ReadConfigFromFile(cfgfile, source)
	if err != nil {
		fmt.Printf("Error:: %v\n", err)
		p.Done <- true
		return nil, err
	}

	// Set the source path
	c.SourcePath = sourcePath
	return c, err
}
func WatchMode(delay int64, p *Process) {
	go func() {
		for true {
			// Get the parts of the config file
			sourcePath := config.SourcePath(source)
			configFileLocation := config.ConfigFile(sourcePath, cfgfile)

			// Set the config file name
			configFileInfo, err := os.Stat(configFileLocation)
			if err != nil {
				log.Printf("Failed to read configuration file from %s\n", configFileLocation)
				continue
			}

			// Read the configuration
			c, err := config.ReadConfigFromFile(cfgfile, source)
			if err != nil {
				log.Printf("Failed to read configuration file from %s\n", configFileLocation)
				continue
			}

			// Point to the actual instance
			configFileInfoInstance := *p.ConfigFileInfo

			// If config time finished
			if !configFileInfo.ModTime().Equal(configFileInfoInstance.ModTime()) {
				log.Printf("Configuration file changed, regenerating whole book\n")
				// Re-generate the whole book
				GenerateWholeBook(p)
				// Save the new configuration file info
				p.ConfigFileInfo = &configFileInfo
				// Done, let's watch again
				continue
			}

			// Read all the layouts for html
			htmlLayouts := c.Layouts["html"]
			indexLayout := htmlLayouts.Index
			pageLayout := htmlLayouts.Page

			// Get the file info for the pageLayout file
			pageLayoutFile := fmt.Sprintf("%s/%s", p.Source, pageLayout)
			pageLayoutFileInfo, err := os.Stat(pageLayoutFile)
			if err != nil {
				log.Printf("Index layout file changed, regenerating whole book\n")
				// Re-generate the whole book
				GenerateWholeBook(p)
				// Update the time
				p.PageLayoutFileInfo = &pageLayoutFileInfo
				continue
			}

			// Get the file info for the pageLayout file
			indexLayoutFile := fmt.Sprintf("%s/%s", p.Source, indexLayout)
			indexLayoutFileInfo, err := os.Stat(indexLayoutFile)
			if err != nil {
				log.Printf("Index layout file changed, regenerating whole book\n")
				// Re-generate the whole book
				GenerateWholeBook(p)
				// Update the time
				p.IndexFileInfo = &indexLayoutFileInfo
				continue
			}

			// Read the page layout file in
			layoutBytes, err := ioutil.ReadFile(pageLayoutFile)
			if err != nil {
				log.Printf("no layout file found for %s\n", pageLayoutFile)
			}

			// Parse the template into an object
			pageTemplate, err := template.New("pageTemplate").Parse(string(layoutBytes))
			if err != nil {
				log.Printf("invalid template found in %s page template file\n", pageLayoutFile)
			}

			// Copy over all the assets
			for _, asset := range c.Assets {
				assetLocation := fmt.Sprintf("%s/%s", p.Source, asset)
				fileContent, err := ioutil.ReadFile(assetLocation)

				// Get the file info for the pageLayout file
				assetFileInfo, err := os.Stat(assetLocation)
				if err == nil {
					modTime := *p.AssetsFileInfo[asset]

					if modTime != nil && modTime.ModTime().Equal(assetFileInfo.ModTime()) {
						continue
					}

					p.AssetsFileInfo[asset] = &assetFileInfo
				}

				if err == nil {
					assetOutputLocation := fmt.Sprintf("%s/%s", c.OutputDirectory, filepath.Base(asset))
					log.Printf("Saving asset to %s\n", assetOutputLocation)

					err = ioutil.WriteFile(assetOutputLocation, fileContent, 0755)
					if err != nil {
						log.Fatalf("Failed to save the asset %s to %s\n", asset, assetOutputLocation)
					}
				} else {
					log.Fatalf("Could not locate the asset %s\n", asset)
				}
			}

			// We only re-generate pages that have changed
			// Read all the pages in
			for pageIndex, page := range c.TableOfContents {
				// Split the file up so we can get the "name"
				fileNameParts := strings.Split(page.File, ".")
				fileName := strings.Join(fileNameParts[0:(len(fileNameParts)-1)], ".")

				// Read the page
				pageFile := fmt.Sprintf("%s/%s", p.Source, page.File)

				// Get the file info for the pageLayout file
				pageFileInfo, err := os.Stat(pageFile)
				if err == nil {
					modTime := *p.PagesFileInfo[page.File]

					if modTime != nil && modTime.ModTime().Equal(pageFileInfo.ModTime()) {
						continue
					}

					log.Printf("Generate page %s\n", page.File)
					p.PagesFileInfo[page.File] = &pageFileInfo
				}

				// Read the page into memory
				data, err := ioutil.ReadFile(pageFile)
				if err != nil {
					continue
				}

				// Render the mardown
				html := p.CustomTransformer.Transform(data)

				// Pass to the template if it's defined
				if pageTemplate != nil {
					// var buffer bytes.Buffer
					buffer := bytes.NewBuffer(nil)
					err = pageTemplate.Execute(buffer, BuildContext(pageIndex, string(html), c))
					if err != nil {
						log.Fatalf("Failed to execute template %s\n", pageLayoutFile)
						os.Exit(0)
					}

					// Save the data as the new page
					html = buffer.Bytes()
				}

				// Let's write the resulting page out
				err = ioutil.WriteFile(fmt.Sprintf("%s/%s.html", c.OutputDirectory, fileName), html, 0755)
				if err != nil {
					continue
				}
			}

			// Just sleep a bit and watch again
			time.Sleep(time.Duration(delay) * time.Millisecond)
		}
	}()

	// Wait until we are done
	<-p.Done
}